web-dev-qa-db-fra.com

Conversion de Java Date en OffsetDateTime

J'ai une valeur eta qui est un OffsetDateTime et j'ai un ScheduleDate qui est un type Date. Si l'eta n'est pas définie, je veux revenir à la date.

Un exemple de la date est Tue Jul 21 10:32:28 PDT 2020. Pour convertir cela, j'ai essayé de faire: OffsetDateTime.ofInstant(dto.getScheduledTime().ToInstant(), ZoneOffset.UTC) On dirait que le décalage utc est incorrect car la date contient déjà PDT, mais en même temps ce n'est pas non plus un timezoneId comme "America/Los_Angeles".

Je suis un peu confus sur la façon de gérer cela.

8
user6728767

tl; dr

OffsetDateTime target, eta;    // Modern Java.time class.
Java.util.Date scheduledDate;  // Terrible legacy class.


if(Objects.isNull(eta)) {   // If no eta, fall back to scheduledDate.
    target = scheduledDate.toInstant().atOffset( ZoneOffset.UTC ); // Never use legacy class `Java.util.Date` -- when encountered, immediately convert to modern `Java.time.Instant`. 
} else {  // Else not null.
    target = eta;
}
return target;

Mieux vaut éviter complètement Java.util.Date. Une fois rencontré, convertissez immédiatement en classe moderne Instant, et oubliez tout sur l'objet Date.

OffsetDateTime target, eta, scheduled;
scheduled = incomingJavaUtilDate.toInstant().atOffset(ZoneOffset.UTC);

target = Objects.isNull(eta) ? scheduledDate : eta;  // Ternary operator. Short way of saying: If eta is null, go with scheduledDate, otherwise go with eta. 
return target;

Date::toString vous ment

Tout d'abord, comprenez que Java.util.Date représente un moment en UTC, toujours en UTC. Cependant, sa méthode toString a la bonne intention d’anti-fonctionnalité terriblement confuse d’appliquer dynamiquement le fuseau horaire par défaut actuel de la JVM. Cela crée la fausse impression que Date a un fuseau horaire alors qu'en fait il ne.

Évitez les anciennes classes de date et d'heure

Deuxièmement, vous mélangez inutilement et tragiquement les très bonnes classes modernes Java.time (OffsetDateTime) avec la terrible date-heure héritée. classes (Date). Ne faites pas cela. Évitez complètement les classes héritées. Ils ont été obsolètes par l'adoption de JSR 31 en 2014.

table of date-time classes in Java, both legacy and modern

Utilisez Java.time

Si remis un Java.util.Date objet, convertir immédiatement en Java.time . Appelez les nouvelles méthodes de conversion ajoutées aux anciennes classes. La classe Instant remplace directement Date, comme un instant en UTC, mais avec une résolution plus fine des nanosecondes par rapport aux millisecondes.

Instant instant = myJavaUtilDate.toInstant();  // Convert from legacy class to modern class.

Vous devriez généralement suivre les moments en UTC. Vous pouvez le faire en tant que Instant ou en tant que OffsetDateTime avec son décalage défini sur ZoneOffset.UTC constant.

OffsetDateTime odt = instant.atOffset(ZoneOffset.UTC);  // Same moment, no change in meaning whatsoever. 

Pour UTC en particulier, il n'y a pas de différence entre le instant et le odt dans notre code ici. Ils représentent tous deux un moment en UTC. La différence est que OffsetDateTime (a) pourrait porter une autre valeur de décalage par rapport à UTC (heures-minutes-secondes), et (b) est plus flexible, comme la génération de texte dans des formats autres que standard - ISO 8601 .

Comprenez qu'un offset-from-UTC est simplement un nombre d'heures, de minutes et de secondes. Rien de plus. Un fuseau horaire , en revanche, est beaucoup plus. Un fuseau horaire est une histoire des changements passés, présents et futurs de l'offset utilisé par les habitants d'une région particulière. Par exemple, les personnes de la région utilisant America/Los_Angeles le fuseau horaire change son décalage par rapport à UTC deux fois par an dans une pratique stupide connue sous le nom de heure d'été (DST) allant de -08: 00 à -07: 00 et vice-versa.

Donc, généralement, un fuseau horaire est préférable à un simple décalage. Par exemple, pour voir votre Date nous nous sommes transformés en Instant à travers l'horloge murale utilisée par la plupart des gens sur la côte ouest des États-Unis, appliquez le fuseau horaire America/Los_Angeles (ZoneId) au Instant pour obtenir un ZonedDateTime.

ZoneId z = ZoneId.of("America/Los_Angeles");
ZonedDateTime zdt = instant.atZone(z);

Vous pouvez revenir à UTC en extrayant un Instant.

Instant instant = zdt.toInstant();

Et à partir de là, revenez à un Java.util.Date (si vous devez, sinon éviter).

Java.util.Date d = Java.util.Date.from(instant);

En fait, le Java.time.Date classe a un fuseau horaire enfoui profondément à l'intérieur. Sans méthode d'accesseur (get/set), elle est inaccessible. Ses comportements ne se rapportent pas à notre discussion ici. Déroutant? Oui. Encore une autre des nombreuses raisons d'éviter les terribles classes de date-heure héritées.

33
Basil Bourque