web-dev-qa-db-fra.com

Comment obtenir ZoneOffset par défaut en Java8?

Avec Java8, nous savons utiliser ZoneId.default() peut obtenir le système par défaut ZoneId, mais comment obtenir le paramètre par défaut ZoneOffset?

Je vois qu'un ZoneId a des "règles" et que chaque règle a un ZoneOffset, est-ce que cela signifie qu'un ZoneId peut avoir plus d'un ZoneOffset?

37
FredSuvn

tl; dr

OffsetDateTime.now().getOffset()

Mais vous devriez probablement utiliser un fuseau horaire plutôt qu'un simple décalage par rapport à UTC.

ZoneId.systemDefault() 

Décalage par rapport au fuseau horaire

Un offset-par-UTC est simplement un nombre d'heures, de minutes et de secondes - rien de plus.

Un fuseau horaire est un historique des modifications passées, présentes et futures de l'offset utilisé par les habitants d'une région donnée. Un fuseau horaire comporte un ensemble de règles permettant de gérer les anomalies, telles que Heure d'été , qui entraînent des décalages du décalage sur des périodes spécifiques.

Fuseau horaire = (Historique des compensations + Règles pour les anomalies)

Donc il vaut mieux utiliser une zone quand on le sait.

Le décalage pour une région varie dans le temps. Par exemple, l'heure d'été aux États-Unis décale le décalage d'une heure pendant environ la moitié de l'année, puis rétablit cette heure au décalage pendant l'autre moitié de l'année. L’objet d’un fuseau horaire est de documenter ces décalages en décalage.

Il n’a donc aucun sens de demander un décalage sans date-heure . Dans America/Los_Angeles , par exemple, cette année, le décalage est de -08:00 mais dans une autre partie de l'année, c'est -07:00 pendant l'heure d'été.

OffsetDateTime

Spécifions donc un moment sous la forme OffsetDateTime , puis extrayons le ZoneOffset .

OffsetDateTime odt = OffsetDateTime.now ();
ZoneOffset zoneOffset = odt.getOffset ();

odt.toString (): 2017-01-02T15: 19: 47.162-08: 00

zoneOffset.toString (): -08: 00

Cette méthode now applique de manière implicite le fuseau horaire par défaut actuel de la machine virtuelle Java. Je vous suggère de toujours l'expliciter en précisant votre fuseau horaire souhaité/attendu. Même si vous voulez la zone par défaut actuelle, indiquez-le explicitement pour préciser vos intentions. Éliminez toute ambiguïté quant à savoir si vous avez prévu le fuseau horaire par défaut ou non, comme cela arrive souvent aux programmeurs. Appel ZoneId.systemDefault .

OffsetDateTime odt = OffsetDateTime.now ( ZoneId.systemDefault () );
ZoneOffset zoneOffset = odt.getOffset ();

ZoneId.systemDefault (). ToString (): America/Los_Angeles

à partir de: 2017-01-02T15: 19: 47.162-08: 00

zoneOffsetOfOdt: -08: 00

Avertissement concernant la zone par défaut: Ce code par défaut peut être modifié à tout moment par n'importe quel code de n'importe quel thread de la machine virtuelle Java. Si important, demandez à l'utilisateur pour leur fuseau horaire prévu.

Vous pouvez demander à l'offset sa durée en nombre total de secondes.

int offsetSeconds = zoneOffset.getTotalSeconds ();

offsetSecondes: -28800

ZonedDateTime

Autre exemple: vous voulez peut-être savoir quelle sera la compensation le jour de Noël cette année au Québec. Spécifiez le fuseau horaire America/Montreal, obtenez un ZonedDateTime , demandez son décalage en tant qu'objet ZoneOffset.

ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate ld = LocalDate.of( 2017 , 12 , 25 );
ZonedDateTime zdtXmas = ld.atStartOfDay( z );
ZoneOffset zoneOffsetXmas = zdtXmas.getOffset();

zdtXmas.toString (): 2017-12-25T00: 00-05: 00 [Amérique/Montréal]

zoneOffsetXmas.toString (): -05: 00

zoneOffsetXmas.getTotalSeconds (): -18000

Table of date-time types in Java, both modern and legacy.

ZoneId

Comme suggéré dans le commentaire de yanys, vous pouvez interroger un ZoneId pour un ZoneOffset particulier en passant un moment en tant que Instant. La classe Instant représente un moment sur la ligne temporelle de UTC avec une résolution de nanosecondes (jusqu'à neuf (9) chiffres d'une fraction décimale).

Ceci est juste un autre itinéraire vers la même destination. Comme avec OffsetDateTime et ZonedDateTime discutés ci-dessus, nous spécifions (a) un fuseau horaire et (b) un moment.

Instant instant = zdtXmas.toInstant();
ZoneOffset zo = z.getRules().getOffset( instant );

Pour ZoneId: Amérique/Montréal au moment: 2017-12-25T05: 00: 00Z le ZoneOffset est: -05: 00

Voir tous ces exemples ’ code en direct sur IdeOne.com .

ZoneOffset.systemDefault - Bug ou fonctionnalité?

La classe ZoneOffset, une sous-classe de ZoneId, est documentée comme héritant de la méthode systemDefault . Cependant, cela ne fonctionne pas réellement.

ZoneOffset zoneOffset = ZoneOffset.systemDefault() ;  // Fails to compile.

erreur: types incompatibles: ZoneId ne peut pas être converti en ZoneOffset

Vous ne savez pas si cet échec de compilation est un bogue ou une fonctionnalité. Comme discuté ci-dessus, il ne me semble pas logique de demander jamais un décalage par défaut avec une date-heure, alors peut-être que le ZoneOffset.systemDefault devrait en effet échouer. Mais la documentation devrait le dire avec une explication.

J'ai essayé de déposer un bogue sur l'incapacité de la doc à résoudre ce problème, mais j'ai abandonné, incapable de déterminer où et comment déposer un tel rapport de bogue.


À propos de Java.time

Le cadre Java.time est intégré à Java 8 et versions ultérieures. Ces classes supplantent l'ancien problème - legacy classes date-heure telles que Java.util.Date , Calendar , & SimpleDateFormat .

Le projet Joda-Time , actuellement en mode de maintenance , conseille de migrer vers le Java.time = cours.

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

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

Où obtenir les classes Java.time?

Le projet ThreeTen-Extra étend Java.time avec des classes supplémentaires. Ce projet est un terrain d’essai pour d’éventuels ajouts à Java.time. Vous pouvez trouver ici quelques classes utiles telles que Interval , YearWeek , YearQuarter , et plus .

116
Basil Bourque