Quelle est la différence entre Instant et LocalDateTime?

256

Je le sais:

  • Instant est plutôt une représentation d'horodatage "technique" (nanosecondes) pour le calcul.
  • LocalDateTime est plutôt une représentation date / horloge incluant des fuseaux horaires pour les humains.

À la fin, l'OMI peut être considérée comme un type pour la plupart des cas d'utilisation d'application. À titre d'exemple: actuellement, j'exécute un travail par lots où je dois calculer une prochaine exécution en fonction des dates et j'ai du mal à trouver un pour / contre entre ces deux types (à part l'avantage de précision en nanosecondes d'Instant et la partie fuseau horaire de LocalDateTime).

Pouvez-vous nommer quelques exemples d'application, où seuls Instant ou LocalDateTime doivent être utilisés?

Edit: Méfiez-vous des documentations mal lues pour LocalDateTime concernant la précision et le fuseau horaire

manuel aldana
la source
Instant est plus élémentaire, enveloppant le standard long pour l'UTC. Pour un lot cron, ce n'est pas un choix si logique.
Joop Eggen
37
Définition incorrecte . LocalDateTimen'a pas de fuseau horaire!
Basil Bourque

Réponses:

834

Tableau de tous les types de date-heure en Java, à la fois modernes et hérités

tl; dr

Instantet LocalDateTimesont deux animaux entièrement différents: l'un représente un moment, l'autre non.

  • Instant représente un moment, un point spécifique de la chronologie.
  • LocalDateTimereprésente une date et une heure. Mais sans fuseau horaire ou décalage par rapport à l'UTC, cette classe ne peut pas représenter un instant . Il représente des moments potentiels sur une plage d'environ 26 à 27 heures, la plage de tous les fuseaux horaires du globe.

Présomption incorrecte

LocalDateTime est plutôt une représentation date / horloge incluant des fuseaux horaires pour l'homme.

Votre déclaration est incorrecte: A LocalDateTimen'a pas de fuseau horaire . Ne pas avoir de fuseau horaire est tout l'intérêt de cette classe.

Pour citer le doc de cette classe:

Cette classe ne stocke ni ne représente un fuseau horaire. Au lieu de cela, il s'agit d'une description de la date, utilisée pour les anniversaires, combinée à l'heure locale telle qu'elle apparaît sur une horloge murale. Il ne peut pas représenter un instant sur la ligne de temps sans informations supplémentaires telles qu'un décalage ou un fuseau horaire.

Signifie donc Local…«pas zoné, pas de décalage».

Instant

entrez la description de l'image ici

An Instantest un moment de la chronologie en UTC , un décompte de nanosecondes depuis l'époque du premier moment de 1970 UTC (en gros, voir le doc de classe pour les détails les plus fins). Étant donné que la plupart de votre logique métier, stockage de données et échange de données doivent être en UTC, il s'agit d'une classe pratique à utiliser souvent.

Instant instant = Instant.now() ;  // Capture the current moment in UTC.

OffsetDateTime

entrez la description de l'image ici

La classe OffsetDateTimeclass représente un moment comme une date et une heure avec un contexte d'un certain nombre d'heures-minutes-secondes avant ou derrière UTC. La quantité de décalage, le nombre d'heures-minutes-secondes, est représentée par leZoneOffset classe.

Si le nombre d'heures-minutes-secondes est nul, an OffsetDateTimereprésente un moment en UTC identique à an Instant.

ZoneOffset

entrez la description de l'image ici

La ZoneOffsetclasse représente un décalage par rapport à UTC , un certain nombre d'heures-minutes-secondes devant UTC ou derrière UTC.

A ZoneOffsetn'est qu'un nombre d'heures-minutes-secondes, rien de plus. Une zone, c'est beaucoup plus, ayant un nom et un historique des changements à compenser. Il est donc toujours préférable d'utiliser une zone que d'utiliser un simple décalage.

ZoneId

entrez la description de l'image ici

Un fuseau horaire est représenté par la ZoneIdclasse.

Un nouveau jour se lève plus tôt à Paris qu'à Montréal , par exemple. Nous devons donc déplacer les aiguilles de l'horloge pour mieux refléter midi (lorsque le soleil est directement au-dessus) pour une région donnée. Plus la distance est / ouest est éloignée de la ligne UTC en Europe occidentale / Afrique, plus le décalage est important.

Un fuseau horaire est un ensemble de règles pour gérer les ajustements et les anomalies tels que pratiqués par une communauté ou une région locale. L'anomalie la plus courante est la folie bien trop populaire connue sous le nom d' heure d'été (DST) .

Un fuseau horaire a l'historique des règles passées, des règles actuelles et des règles confirmées pour un avenir proche.

Ces règles changent plus souvent que vous ne le pensez. Assurez-vous de garder à jour les règles de votre bibliothèque date-heure, généralement une copie de la base de données «tz» . La mise à jour est plus facile que jamais maintenant dans Java 8 avec Oracle libérant un outil de mise à jour de fuseau horaire .

Indiquez un nom de fuseau horaire approprié dans le format Continent/Region, tels que America/Montreal, Africa/Casablancaou Pacific/Auckland. N'utilisez jamais l'abréviation de 2 à 4 lettres telles que ESTou ISTcar ce ne sont pas de vrais fuseaux horaires, ni standardisés, ni même uniques (!).

Fuseau horaire = décalage + règles d'ajustement

ZoneId z = ZoneId.of( Africa/Tunis ) ; 

ZonedDateTime

entrez la description de l'image ici

Pensez ZonedDateTimeconceptuellement Instantà un assigné ZoneId.

ZonedDateTime = (Instant + ZoneId)

Pour capturer le moment actuel tel qu'il apparaît dans l'heure de l'horloge murale utilisée par les habitants d'une région particulière (un fuseau horaire):

ZonedDateTime zdt = ZonedDateTime.now( z ) ;  // Pass a `ZoneId` object such as `ZoneId.of( "Europe/Paris" )`. 

La quasi-totalité de votre backend, base de données, logique métier, persistance des données, échange de données devraient tous être en UTC. Mais pour la présentation aux utilisateurs, vous devez vous ajuster dans un fuseau horaire attendu par l'utilisateur. C'est le but de la ZonedDateTimeclasse et des classes de formateur utilisées pour générer des représentations String de ces valeurs date-heure.

ZonedDateTime zdt = instant.atZone( z ) ;
String output = zdt.toString() ;                 // Standard ISO 8601 format.

Vous pouvez générer du texte au format localisé à l'aide de DateTimeFormatter.

DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( Locale.CANADA_FRENCH ) ; 
String outputFormatted = zdt.format( f ) ;

mardi 30 avril 2019 à 23 h 22 min 55 s heure de l'Inde

LocalDate, LocalTime,LocalDateTime

Diagramme montrant uniquement un calendrier pour une <code> LocalDate </code>.

Diagramme montrant uniquement une horloge pour un <code> LocalTime </code>.

Diagramme montrant un calendrier et une horloge pour un <code> LocalDateTime </code>.

Les classes de date et heure « locale », LocalDateTime, LocalDate, LocalTime, sont un autre type de créature. Ils ne sont liés à aucune localité ou fuseau horaire. Ils ne sont pas liés à la chronologie. Ils n'ont aucune signification réelle jusqu'à ce que vous les appliquiez à une localité pour trouver un point sur la chronologie.

Le mot «local» dans ces noms de classe peut être contre-intuitif pour les non-initiés. Le mot signifie n'importe quelle localité, ou chaque localité, mais pas une localité particulière.

Ainsi, pour les applications professionnelles, les types "locaux" ne sont pas souvent utilisés car ils représentent simplement l'idée générale d'une date ou d'une heure possible et non d'un moment spécifique sur la chronologie. Les applications professionnelles ont tendance à se soucier du moment exact où une facture est arrivée, un produit expédié pour le transport, un employé a été embauché ou le taxi a quitté le garage. Les développeurs d'applications métier utilisent donc Instantet les ZonedDateTimeclasses le plus souvent.

Alors, quand utiliserions-nous LocalDateTime? Dans trois situations: où nous voulons appliquer une certaine date et heure à plusieurs endroits, où nous prenons des rendez-vous ou où nous avons un fuseau horaire prévu mais indéterminé. Notez qu'aucun de ces trois cas n'est un seul point spécifique sur la chronologie, aucun d'entre eux n'est un moment.

Un moment de la journée, plusieurs moments

Parfois, nous voulons représenter un certain moment de la journée à une certaine date, mais nous voulons l'appliquer à plusieurs localités à travers les fuseaux horaires.

Par exemple, "Noël commence à minuit le 25 décembre 2015" est un LocalDateTime. Minuit frappe à différents moments à Paris qu'à Montréal, et à nouveau différent à Seattle et à Auckland .

LocalDate ld = LocalDate.of( 2018 , Month.DECEMBER , 25 ) ;
LocalTime lt = LocalTime.MIN ;   // 00:00:00
LocalTime ldt = LocalDateTime.of( ld , lt ) ;  // Xmas morning anywhere. 

Un autre exemple, «Acme Company a pour politique que l'heure du déjeuner commence à 12 h 30 dans chacune de ses usines à travers le monde» est a LocalTime. Pour avoir un vrai sens, vous devez l'appliquer à la chronologie pour comprendre le moment de 12h30 à l' usine de Stuttgart ou de 12h30 à l' usine de Rabat ou de 12h30 à l' usine de Sydney .

Prise de rendez-vous

Une autre situation à utiliser LocalDateTimeest de réserver des événements futurs (ex: rendez-vous chez le dentiste). Ces nominations pourraient être suffisamment éloignées à l'avenir pour que vous risquiez que les politiciens redéfinissent le fuseau horaire. Les politiciens donnent souvent peu d'avertissement, voire aucun avertissement. Si vous voulez dire "15 h le 23 janvier prochain", quelle que soit la façon dont les politiciens peuvent jouer avec l'horloge, vous ne pouvez pas enregistrer un instant - cela verrait 15 h se transformer en 14 h ou 16 h si cette région adoptait ou abandonnait l'heure d'été, par exemple.

Pour les rendez-vous, stockez a LocalDateTimeet a ZoneId, conservés séparément. Plus tard, lors de la génération d'un planning, à la volée, déterminez un moment en appelant LocalDateTime::atZone( ZoneId )pour générer un ZonedDateTimeobjet.

ZonedDateTime zdt = ldt.atZone( z ) ;  // Given a date, a time-of-day, and a time zone, determine a moment, a point on the timeline.

Si nécessaire, vous pouvez vous ajuster sur UTC. Extraire un Instantdu ZonedDateTime.

Instant instant = zdt.toInstant() ;  // Adjust from some zone to UTC. Same moment, same point on the timeline, different wall-clock time.

Zone inconnue

Certaines personnes peuvent utiliser LocalDateTimedans une situation où le fuseau horaire ou le décalage est inconnu.

Je considère que ce cas est inapproprié et imprudent. Si une zone ou un décalage est prévu mais indéterminé, vous avez de mauvaises données. Ce serait comme stocker un prix d'un produit sans connaître la devise souhaitée. Pas une bonne idée.

Tous les types date-heure

Pour être complet, voici un tableau de tous les types de date-heure possibles, à la fois modernes et hérités en Java, ainsi que ceux définis par la norme SQL. Cela pourrait aider à placer les classes Instant& LocalDateTimedans un contexte plus large.

Tableau de tous les types date-heure en Java (à la fois moderne et hérité) ainsi qu'en standard SQL.

Notez les choix étranges faits par l'équipe Java lors de la conception de JDBC 4.2. Ils ont choisi de prendre en charge tous les temps java.time … à l'exception des deux classes les plus utilisées: Instant& ZonedDateTime.

Mais ne vous inquiétez pas. Nous pouvons facilement convertir dans les deux sens.

Conversion Instant.

// Storing
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
myPreparedStatement.setObject(  , odt ) ;

// Retrieving
OffsetDateTime odt = myResultSet.getObject(  , OffsetDateTime.class ) ;
Instant instant = odt.toInstant() ;

Conversion ZonedDateTime.

// Storing
OffsetDateTime odt = zdt.toOffsetDateTime() ;
myPreparedStatement.setObject(  , odt ) ;

// Retrieving
OffsetDateTime odt = myResultSet.getObject(  , OffsetDateTime.class ) ;
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = odt.atZone( z ) ; 

À propos de java.time

Le framework java.time est intégré à Java 8 et versions ultérieures. Ces classes supplantent les anciens gênants hérités des classes date-heure tels que java.util.Date, Calendar, et SimpleDateFormat.

Le projet Joda-Time , désormais en mode maintenance , conseille la migration vers les classes java.time .

Pour en savoir plus, consultez le didacticiel Oracle . Et recherchez Stack Overflow pour de nombreux exemples et explications. La spécification est JSR 310 .

Vous pouvez échanger des objets java.time directement avec votre base de données. Utilisez un pilote JDBC compatible avec JDBC 4.2 ou version ultérieure. Pas besoin de chaînes, pas besoin de java.sql.*cours.

Où obtenir les classes java.time?

  • Java SE 8 , Java SE 9 , Java SE 10 et versions ultérieures
    • Intégré.
    • Une partie de l'API Java standard avec une implémentation groupée.
    • Java 9 ajoute quelques fonctionnalités et correctifs mineurs.
  • Java SE 6 et Java SE 7
    • Une grande partie de la fonctionnalité java.time est backportée sur Java 6 et 7 dans ThreeTen-Backport .
  • Android
    • Versions ultérieures des implémentations de bundles Android des classes java.time.
    • Pour les versions antérieures d'Android (<26), le projet ThreeTenABP adapte ThreeTen-Backport (mentionné ci-dessus). Voir Comment utiliser ThreeTenABP… .

Tableau de la bibliothèque java.time à utiliser avec quelle version de Java ou Android

Le projet ThreeTen-Extra étend java.time avec des classes supplémentaires. Ce projet est un terrain d'essai pour de futurs ajouts possibles à java.time. Vous trouverez peut - être des classes utiles ici, comme Interval, YearWeek, YearQuarteret plus .

Basil Bourque
la source
40
Très bonne réponse. Je pense qu'une certaine confusion (au moins la mienne) vient de la Localdénomination. Mon intuition pour les Localmoyens par rapport à où je suis ET quand je suis (?!), Ce qui me fait croire que ce serait bien ce qu'est un ZonedDateTime.
mkobit
4
Oui, c'est déroutant. C'est pourquoi java.time a intelligemment ajouté le mot 'Zoned' au DateTimenom de classe utilisé par son prédécesseur Joda-Time (producteur ZonedDateTime), pour souligner la différence avec les classes "locales". Considérez le nom «local» comme un raccourci pour «avoir besoin d'être appliqué à une localité particulière».
Basil Bourque
2
Le préfixe avec le mot Localpeut également avoir été un moyen de se différencier du package java.util, bien que je pense qu'il aurait pu y avoir un meilleur choix de mot.
vphilipnyc
2
@simonh Au contraire… Lorsque ce nouvel employé signera ses papiers d'embauche définissant leurs avantages sociaux, y compris l'assurance-vie, puis que la nouvelle embauche sortira pour un café seulement pour être frappée et tuée par un camion, il y aura beaucoup de gens comme en tant que directeurs des ressources humaines, agents d'assurance et avocats qui voudront connaître le moment précis où ce nouvel emploi est entré en vigueur.
Basil Bourque
2
@simonh Oui, il y a des cas où la date-heure "locale" est appropriée. Outre ceux mentionnés dans ma réponse, un autre cas courant dans les affaires concerne les rendez-vous à plus de deux mois dans le futur, suffisamment loin pour que les politiciens puissent modifier les règles de fuseau horaire, généralement avec peu d'avertissement. Les politiciens effectuent fréquemment ces changements, tels que la modification des dates lors de l'activation / désactivation de l'heure d'été (DST) ou le maintien permanent de l'heure d'été / heure d'été.
Basil Bourque
20

Une différence principale est la Localpartie de LocalDateTime. Si vous vivez en Allemagne et créez une LocalDateTimeinstance et que quelqu'un d'autre vit aux États-Unis et crée une autre instance au même moment (à condition que les horloges soient correctement réglées) - la valeur de ces objets serait en fait différente. Cela ne s'applique pas à Instant, qui est calculé indépendamment du fuseau horaire.

LocalDateTimestocke la date et l'heure sans fuseau horaire, mais sa valeur initiale dépend du fuseau horaire. Instantce n'est pas le cas.

De plus, LocalDateTimefournit des méthodes pour manipuler les composants de date comme les jours, les heures, les mois. Et Instantnon.

à part l'avantage de précision en nanosecondes d'Instant et la partie fuseau horaire de LocalDateTime

Les deux classes ont la même précision. LocalDateTimene stocke pas de fuseau horaire. Lisez javadocs attentivement, car vous pouvez faire une grosse erreur avec de telles hypothèses invalides: Instant et LocalDateTime .

Dariusz
la source
désolé pour la mauvaise lecture de la partie sur la zone + précision. Désolé de répéter le post ci-dessus: En considérant une seule application de fuseau horaire, dans quels cas d'utilisation préféreriez-vous LocalDateTime ou vice versa?
manuel aldana
1
Je prendrais LocalDateTime chaque fois que j'ai besoin de dates et / ou d'heures. En heures, minutes ou plus. J'utiliserais Instant pour mesurer les temps d'exécution, par exemple, ou stocker un champ interne de qc se produisant sur-le-champ. Calcul des prochaines courses, comme dans votre cas? LocalDateTime semble approprié, mais c'est une opinion. Comme vous l'avez dit, les deux peuvent être utilisés.
Dariusz
Pouvez-vous nous en dire plus LocalDateTime stores date and time without timezone, but it's initial value is timezone dependent? quelle est la valeur initiale et comment dépend-elle du fuseau horaire? Merci.
Max
12

Vous vous trompez LocalDateTime: il ne stocke aucune information de fuseau horaire et il a une précision en nanosecondes. Citant le Javadoc (c'est moi qui souligne):

Une date-heure sans fuseau horaire dans le système de calendrier ISO-8601 , telle que 2007-12-03T10: 15: 30.

LocalDateTime est un objet date-heure immuable qui représente une date-heure, souvent vue comme année-mois-jour-heure-minute-seconde. D'autres champs de date et d'heure, tels que jour de l'année, jour de la semaine et semaine de l'année, sont également accessibles. Le temps est représenté avec une précision en nanosecondes . Par exemple, la valeur "2 octobre 2007 à 13: 45.30.123456789" peut être stockée dans un LocalDateTime.

La différence entre les deux est qu'elle Instantreprésente un décalage par rapport à l'époque (01-01-1970) et, en tant que telle, représente un instant particulier sur la ligne du temps. Deux Instantobjets créés au même moment dans deux endroits différents de la Terre auront exactement la même valeur.

Tunaki
la source
En considérant une seule application de fuseau horaire, dans quels cas d'utilisation préféreriez-vous LocalDateTime ou vice versa?
manuel aldana
3
@manuelaldana C'est plus une question de goût. Je préférerais LocalDateTime pour tout ce qui concerne l'utilisateur (anniversaire ...) et Instant pour tout ce qui est lié à la machine (temps d'exécution ...).
Tunaki
2
@manuelaldana Une application à fuseau horaire unique est rare, voire inexistante. Vous pourriez vous en tirer en ignorant les fuseaux horaires pour une petite application que vous avez préparée pour votre club de musique baroque local. Mais dès que vous devez publier un événement pour les personnes qui voyagent (et traversent les fuseaux horaires), elles voudront que les données soient liées à un fuseau horaire afin que leur application de calendrier puisse s'adapter selon les besoins. Je vous suggère d'apprendre à travailler correctement avec les fuseaux horaires dans toutes vos applications.
Basil Bourque
@Tunaki Votre utilisation du mot «décalage» dans le dernier paragraphe est distrayante. Ce mot a une certaine signification dans le travail date-heure, donc son utilisation ici dans ce contexte pourrait être inutile.
Basil Bourque
0

Instant correspond à l'heure sur le méridien premier (Greenwich).

Alors que par LocalDateTimerapport aux paramètres de fuseau horaire du système d'exploitation, et

ne peut pas représenter un instant sans informations supplémentaires telles qu'un décalage ou un fuseau horaire.

user2418306
la source
2
Instant est basé sur UTC et non sur GMT.
Torsten Ojaperv