tl; dr
Instant
et LocalDateTime
sont 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.
LocalDateTime
repré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 LocalDateTime
n'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
An Instant
est 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
La classe OffsetDateTime
class 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 OffsetDateTime
représente un moment en UTC identique à an Instant
.
ZoneOffset
La ZoneOffset
classe représente un décalage par rapport à UTC , un certain nombre d'heures-minutes-secondes devant UTC ou derrière UTC.
A ZoneOffset
n'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
Un fuseau horaire est représenté par la ZoneId
classe.
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/Casablanca
ou Pacific/Auckland
. N'utilisez jamais l'abréviation de 2 à 4 lettres telles que EST
ou IST
car 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
Pensez ZonedDateTime
conceptuellement 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 ZonedDateTime
classe 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
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 Instant
et les ZonedDateTime
classes 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 LocalDateTime
est 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 LocalDateTime
et 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 ZonedDateTime
objet.
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 Instant
du 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 LocalDateTime
dans 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
& LocalDateTime
dans un contexte plus large.
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… .
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
, YearQuarter
et plus .