Nous créons une application de planification et nous devons représenter le calendrier disponible de quelqu'un pendant la journée, quel que soit le champ de l'heure dans lequel ils se trouvent. Prendre une queue de l'intervalle de Joda Time, qui représente un intervalle de temps absolu entre deux cas ( Commencez inclusive, fin exclusive), nous avons créé un localinterval. Le localInterval est composé de deux locaux (début inclusif, exclusif exclusif), et nous avons même fait une classe pratique pour la persister en hibernate.
Par exemple, si une personne est disponible de 13h00 à 17h00, nous le ferions Créez: P>
new LocalInterval(new LocalTime(23, 0), new LocalTime(24, 0));
9 Réponses :
Ce n'est pas une faille de conception. aussi, que se passe-t-il lorsque vous souhaitez représenter un intervalle entre, dire de 21h et 3h 3h? p> Qu'est-ce qui ne va pas avec ceci: p> Il vous suffit de gérer la possibilité que l'heure de fin puisse être "avant" l'heure de début et ajoutez un Jour si nécessaire, et espérons simplement que personne ne veuille représenter un intervalle plus de 24 heures. P> Alternativement, représentez l'intervalle de combinaison d'un localdate code> ne gère pas
(24,0) code> car il n'y a pas de 24:00.
localDate code> et d'une durée
code> ou
période code>. Qui supprime le problème "plus long que 24 heures". P> p>
"[T] Voici rien de 24:00". En effet il y a. Voir ISO 8601-2004 Section 4.2.3 "Minuit". Parce que ma fin est exclusive, c'est exactement ce que je veux.
Ce qui ne va pas avec l'exemple que vous avez donné est qu'il représente un intervalle négatif, de 23h00 à 00h00, ce qui s'est produit 11 heures plus tôt. Considérons l'intervalle de 00h00 à 00h00 --- Est-ce un intervalle sans longueur ou un intervalle pour toute la journée (ignorer les changements de DST)? Ce devrait être le premier --- un intervalle de toute la journée, fin exclusif, serait 00h00 à 24h00. Cela fonctionnerait tous brillamment et être conforme à ISO 8601 s'il n'étaient pas pour une seule ligne de code quelque part en jetant une exception car elle n'aime pas la valeur 24.
Bien après 23:59:59 vient 00:00:00 le lendemain. Alors peut-être utiliser un Bien que depuis que vos temps de début et de fin sont inclus, 23:59:59 est vraiment ce que vous voulez de toute façon. Cela inclut la 59ème seconde de la 59e minute de la 23e heure et termine la plage exactement sur 00:00:00. P>
Il n'y a pas de 24h00 (lorsque vous utilisez localTime code> de
0, 0 code> au prochain jour de calendrier? p>
localTime code>). p>
Désolé, ma question originale avait une faute de frappe. Je voulais dire "fin exclusivité", alors ce que je veux, c'est 24h00. Il y a en effet une telle chose que 24h00. Voir ISO 8601-2004 Section 4.2.3 "Minuit". Parce que ma fin est exclusive, c'est exactement ce que je veux.
@ Garrett-Wilson - Après avoir lu à travers certaines des documents Joda, j'ai quelques suggestions. D'abord, avez-vous essayé d'utiliser le localTime.midnight code> constante? Deuxièmement, quelle dit la spécification et ce que la mise en œuvre ne fait pas nécessairement la même chose. Pouvez-vous essayer quelque chose comme
system.out.println (nouveau localtime (12,0) .getchronologie (). Heure du jour (). GetMaximumValue ()) code>? Si la valeur est inférieure à 24, puis 24h00 n'existe pas dans la mise en œuvre. Ce qui pourrait être quelque chose que vous pouvez augmenter comme un bogue dans Joda.
"Bien après 23:59:59 vient 00:00:00 le lendemain." Pas nécessairement. Parfois, après 23:59:59 vient 23:59:60 - HPIERS.OBSPM. fr / iers / bulc / bulc / bulleinc.dat
"Il n'y a pas de 24h00." est inexact. Localtime ne supporte pas les jours 23:59 Mais cela ne veut pas dire qu'ils n'existent pas. GTFS fonctionne sur> 24 heures sur 24. développeurs.google.com/transit/gtfs/reeference/#stop_TMESTXT
L'heure 24:00 est une difficile. Pendant que nous, les humains, pouvons comprendre ce que l'on entend, codant une API pour représenter que, sans avoir un impact négatif sur tout le reste qui me semble impossible. P>
La valeur 24 étant invalide est profondément codée dans Joda-Time - essayant de supprimer, elle aurait des implications négatives dans de nombreux endroits. Je ne recommanderais pas d'essayer de le faire. P>
Pour votre problème, l'intervalle local doit être composé d'un (localtime, localtime, jours) code> ou
(localtime, période) code>. Ce dernier est légèrement plus flexible. Ceci est nécessaire pour prendre en charge correctement un intervalle de 23h00 à 03h00. P>
Alors, considérez comment votre proposition de (localtime, période) aurait travaillé le 13 mars 2011 aux États-Unis. Si je marque ma disponibilité dimanche de 00 à 12h00: 00, l'utilisation de votre approche utiliserait (00:00, 12 heures). Parce que nous avons perdu une heure le 13 mars, votre représentation produirait 00h00 à 13h00 pour ce jour-là, d'ajouter 12 heures à la date d'heure de minuit donnerait 13h00. Si j'avais plutôt gardé l'heure de fin comme une heure locale, la résolution de 12h00 à la date de minuit me donnerait le temps correct - - l'intervalle de 2011-03-13 serait plus court en raison de la DST.
Je trouve proposition de Jodastephen de Considérant le 13 mars 2011 et votre disponibilité dimanche à partir de 00: 00-12: 00, vous auriez Une disponibilité de Dites 15: 00-24: 00 Vous pouvez ensuite coder comme Bien sûr, il serait bien d'utiliser une locale 24h00 directement et ISO 8601 est conforme, mais cela ne semble pas possible sans changer beaucoup à l'intérieur de Jodatime, cette approche semble donc le moindre mal. P>
Et dernier mais surtout, vous pourriez même prolonger la barrière d'une seule journée avec quelque chose comme (localtime, localtime, jours) code> acceptable. p>
(00:00, 12:00, 0) code> qui étaient en fait 11 heures car de dst. p>
(15:00, 00:00, 1) code> qui serait étendu à 2011-03-13T15: 00 - 2011 -03-14t00: 00 Whileat La fin serait souhaitée 2011-03-13T24: 00. Cela signifie que vous utiliseriez une heure locale de 00:00 lors de la prochaine journée de calendrier, comme déjà aroth proposé. P>
(16:00, 05:00, 1) code> ... p>
Votre problème peut être encadré comme définissant un intervalle sur un domaine qui s'envole. Votre min est 00:00, et votre max est 24h00 (non inclusif).
Supposons que votre intervalle soit défini comme (inférieur, supérieur). Si vous avez besoin de cette version inférieure Je ne sais pas si votre demande de planification impliquerait des intervalles enveloppants, mais si vous allez aller à (21h00, 24h00) sans impliquer des jours, je ne vois pas ce qui va vous empêcher de demander (21:00, 02h00) sans impliquer des jours (conduisant ainsi à une dimension enveloppante). P> Si votre conception est soumise à une mise en œuvre enveloppante, les opérateurs d'intervalles sont assez trivial. p> par exemple (en pseudo-code): p> Dans ce cas, j'ai trouvé qu'écrire une enveloppe autour de Joda-Time Mise en œuvre Les opérateurs sont assez simples et réduisent l'impédance entre la pensée / les mathématiques et l'API. Même si c'est juste pour l'inclusion de 24h00 à 00h00 à 00h00. P> Je suis d'accord que l'exclusion de 24 heures m'a énervé au début, et ce sera bien si quelqu'un a offert un Solution. Heureusement pour moi, étant donné que mon utilisation des intervalles de temps est dominée par une sémantique enveloppante, je me retrouve toujours avec un wrapper, qui résout incidemment l'exclusion de 24h00. P> P>
La solution que nous avons finalement rendue était d'utiliser 00:00 comme autonome pour 24h00, avec la logique tout au long de la classe et le reste de la demande d'interprétation de cette valeur locale. C'est un véritable kludge, mais c'est la chose la moins intrusive et la moins élégante que je pouvais proposer.
Premièrement, la classe localeTheureInterval conserve un drapeau interne de savoir si le point d'extrémité d'intervalle est fin-de-jour minuit (24h00) . Ce drapeau ne sera vrai que si l'heure de fin est 00:00 (égale à localtime.midnight). P> Par défaut, le constructeur considère 00:00 à commencer par défaut. -day, mais il y a un constructeur alternatif pour la création manuelle d'un intervalle qui va toute la journée: p> Il y a une raison pour laquelle ce constructeur n'a pas seulement une heure de début et un drapeau "est une fin de journée": lorsqu'il est utilisé avec une interface utilisateur avec une liste déroulante de fois, nous ne savons pas si l'utilisateur choisira 00:00 (qui est rendu comme 24h00), mais nous Sachez que lorsque la liste déroulante est pour la fin de la gamme, dans notre cas d'utilisation, cela signifie 24h00. (Bien que localTimeInterval permet des intervalles vides, nous ne leur permettons pas dans notre application.) P> La vérification des chevauchements nécessite une logique spéciale pour prendre soin de 24:00: P> final Time startTime = asTime(localTimeInterval.getStart());
final Time endTime = localTimeInterval.isEndOfDay() ? TIME_2400 : asTime(localTimeInterval.getEnd());
Hibernate.TIME.nullSafeSet(statement, startTime, index);
Hibernate.TIME.nullSafeSet(statement, endTime, index + 1);
Pour une application de planification, je pense que est i> la solution la plus élégante. Combien de fois j'ai eu des problèmes par quelqu'un d'Outlook essayant de représenter leur «journée entière» en faisant correspondre l'heure exacte: passer cela dans nos différences de fuseau horaire, et tout notre calendrier est un gâchis. C'est exactement la raison pour laquelle dans Outlook, vous avez une bascule séparée pour représenter une journée entière.
Ceci est notre mise en œuvre du TIMEIVALL, utilisant NULL à la date de fin pour la fin de la journée. Il prend en charge les chevauchements () et contient des méthodes () et est également basée sur Joda-Time. Il prend en charge des intervalles de couvrant plusieurs jours.
/** * Description: Immutable time interval<br> * The start instant is inclusive but the end instant is exclusive. * The end is always greater than or equal to the start. * The interval is also restricted to just one chronology and time zone. * Start can be null (infinite). * End can be null and will stay null to let the interval last until end-of-day. * It supports intervals spanning multiple days. */ public class TimeInterval { public static final ReadableInstant INSTANT = null; // null means today // public static final ReadableInstant INSTANT = new Instant(0); // this means 1st jan 1970 private final DateTime start; private final DateTime end; public TimeInterval() { this((LocalTime) null, null); } /** * @param from - null or a time (null = left unbounded == LocalTime.MIDNIGHT) * @param to - null or a time (null = right unbounded) * @throws IllegalArgumentException if invalid (to is before from) */ public TimeInterval(LocalTime from, LocalTime to) throws IllegalArgumentException { this(from == null ? null : from.toDateTime(INSTANT), to == null ? null : to.toDateTime(INSTANT)); } /** * create interval spanning multiple days possibly. * * @param start - start distinct time * @param end - end distinct time * @throws IllegalArgumentException - if start > end. start must be <= end */ public TimeInterval(DateTime start, DateTime end) throws IllegalArgumentException { this.start = start; this.end = end; if (start != null && end != null && start.isAfter(end)) throw new IllegalArgumentException("start must be less or equal to end"); } public DateTime getStart() { return start; } public DateTime getEnd() { return end; } public boolean isEndUndefined() { return end == null; } public boolean isStartUndefined() { return start == null; } public boolean isUndefined() { return isEndUndefined() && isStartUndefined(); } public boolean overlaps(TimeInterval other) { return (start == null || (other.end == null || start.isBefore(other.end))) && (end == null || (other.start == null || other.start.isBefore(end))); } public boolean contains(TimeInterval other) { return ((start != null && other.start != null && !start.isAfter(other.start)) || (start == null)) && ((end != null && other.end != null && !other.end.isAfter(end)) || (end == null)); } public boolean contains(LocalTime other) { return contains(other == null ? null : other.toDateTime(INSTANT)); } public boolean containsEnd(DateTime other) { if (other == null) { return end == null; } else { return (start == null || !other.isBefore(start)) && (end == null || !other.isAfter(end)); } } public boolean contains(DateTime other) { if (other == null) { return start == null; } else { return (start == null || !other.isBefore(start)) && (end == null || other.isBefore(end)); } } @Override public String toString() { final StringBuilder sb = new StringBuilder(); sb.append("TimeInterval"); sb.append("{start=").append(start); sb.append(", end=").append(end); sb.append('}'); return sb.toString(); } }
Par souci d'exhaustivité Ce test échoue:
@Test() public void testJoda() throws DGConstraintViolatedException { DateTimeFormatter simpleTimeFormatter = DateTimeFormat.forPattern("HHmm"); LocalTime t1 = LocalTime.parse("0000", simpleTimeFormatter); LocalTime t2 = LocalTime.MIDNIGHT; Assert.assertTrue(t1.isBefore(t2)); }
Cette question est ancienne, mais beaucoup de ces réponses se concentrent sur Joda Time, et ne répondent que partiellement le vrai problème sous-jacent: p>
Le modèle dans le code de l'OP ne correspond pas à la réalité, c'est la modélisation. P>
Malheureusement, puisque vous ne semblez se soucier de la condition limite entre les jours, votre « sinon élégant modèle » est pas un bon match pour le problème que vous modélisez. Vous avez utilisé une paire de valeurs de temps pour représenter des intervalles. Toute tentative de simplifier le modèle vers le bas à une paire de fois simplifie en dessous de la complexité du problème du monde réel strong>. limites de jour existent bien dans la réalité et une paire de fois desserre ce type d'information. Comme toujours, plus de simplification de la complexité des résultats à la suite de restaurer ou compenser les informations manquantes. complexité réelle ne peut être poussé autour d'une partie du code à l'autre. p>
La complexité de la réalité ne peut être éliminé avec la magie des « cas d'utilisation non pris en charge ». P>
Votre modèle serait logique dans un espace de problème où l'on ne se souciait pas combien de jours pourraient exister entre les heures de début et de fin. Cet espace de problème ne correspond pas à la plupart des problèmes du monde réel. Par conséquent, il est pas surprenant que Joda Le temps ne supporte pas bien. L'utilisation de 25 valeurs pour les heures lieu (0-24) est une odeur code et habituellement des points de faiblesse dans la conception. Il n'y a que 24 heures dans la journée pour 25 valeurs ne doivent pas être nécessaires! P>
Notez que puisque vous n'êtes pas capturez la date de chaque fin de Vous devriez utiliser soit une date / heure de début et la durée, ou à une date / heure de début et une date / heure de fin (y compris début, à la fin exclusive est un bon choix par défaut ). En utilisant une durée devient difficile si vous avez l'intention d'afficher l'heure de fin à cause de choses comme le temps de l'heure d'été, les années bissextiles et secondes bissextiles. D'autre part en utilisant une date de fin devient aussi difficile si vous vous attendez à afficher la durée. Le stockage à la fois bien sûr est dangereuse car elle viole le principe DRY . Si je devais écrire une telle classe je stocker une date de fin / heure et la logique pour résumer l'obtention de la durée via une méthode sur l'objet. Que les clients à sens unique de la classe de classe ne sont pas tous avec leur propre code pour calculer la durée. p>
Je coder un exemple, mais il y a une option encore mieux. Utilisez la norme Intervalle classe de temps Joda, qui accepte déjà un instant de début et durée ou fin instantanée. Il sera également et calculer heureusement la durée ou l'heure de fin pour vous. Malheureusement, JSR-310 ne dispose pas d'une classe d'intervalle ou similaire. (Bien que l'on peut utiliser ThreeTenExtra pour compenser cela) p>
Les gens relativement lumineux à Joda temps et Sun / Oracle ( JSR-310 ) à la fois bien réfléchi à ces problèmes. Vous pourriez être plus intelligent qu'eux. C'est possible. Cependant, même si vous êtes une ampoule lumineuse, votre 1 heure ne va probablement pas accomplir ce qu'ils ont passé des années sur. Sauf si vous êtes quelque part dans un cas limite ésotérique, il est généralement perdre de temps et d'argent à dépenser effort seconde les deviner. (Bien sûr, au moment de l'OP JSR-310 n'a pas été complète ...) p>
Nous espérons que les gens vont figurant ci-dessus qui trouvent cette question lors de la conception ou la résolution des problèmes similaires. P> LocalInterval code>, votre classe ne tient pas non plus d'informations suffisantes pour tenir compte de l'heure d'été.
[00:30:00 04:00:00 A) code> est généralement 3,5 heures de temps, mais pourrait aussi être 2,5 ou 4,5 heures. P>
Du contexte de votre question, je suppose que vous devinez dire "le localInterval est composé de deux locales (début inclusivement, fin exclusivité), ..."
@Musigenèse: Oui, c'était une faute de frappe. J'ai mis à jour la question pour indiquer la fin exclusive. Merci.
Question très intéressante. Cela m'a inspiré il y a quelque temps pour introduire la fonctionnalité de 24h00 dans ma propre date / heure de la bibliothèque de la bibliothèque4j. Son pendentif similaire à
localtime code>, nommément
plainte code> prend en charge la plage légèrement plus large 00: 00/24: 00. Et j'ai constaté que cette fonctionnalité ne pose aucun problème (l'ordre de temps est toujours clair) mais peut aider à résoudre d'autres problèmes de manière plus élégante (par exemple, l'IANA-TZDB utilise la valeur 24:00, également).