将Java Date转换为OffsetDateTime

问题描述 投票:1回答:1

我的eta值是OffsetDateTime,我有一个DateDate类型的scheduledDate。如果没有设置eta,我想回到日期。

日期的一个例子是Tue Jul 21 10:32:28 PDT 2020。为了转换这个,我尝试了: OffsetDateTime.ofInstant(dto.getScheduledTime().ToInstant(), ZoneOffset.UTC) 感觉就像utc偏移是错误的,因为Date已经有了PDT,但同时它也不是像“America / Los_Angeles”那样的时区。

我对如何处理这个问题感到有些困惑。

java spring java-time java-date
1个回答
17
投票

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 ;

最好完全避免java.util.Date。遇到时,立即转换为现代类Instant,并忘记所有关于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 lies to you

首先,要了解java.util.Date代表UTC时刻,始终是UTC†。但是,它的toString方法具有动态应用JVM当前默认时区的非常混乱的反特征。这造成了错误的印象,即Date有一个时区,实际上它没有†。

Avoid legacy date-time classes

其次,你将非常好的现代java.time类(OffsetDateTime)与非常可怕的遗留日期时间类(Date)混合在一起。不要这样做。完全避免遗留类。它们在2014年被JSR 310采用后被淘汰。

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

Use java.time

如果交了一个java.util.Date对象,立即转换为java.time。调用添加到旧类的新转换方法。 Instant类直接替换Date,作为UTC的一个时刻,但具有更精细的分辨率纳秒与毫秒。

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

您通常应该跟踪UTC中的时刻。您可以将此作为InstantOffsetDateTime,其偏移量设置为ZoneOffset.UTC常量。

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

特别是对于UTC,我们的代码中的instantodt之间没有区别。它们都代表了UTC时刻。不同之处在于OffsetDateTime(a)可以携带替代的UTC偏移值(小时 - 分钟 - 秒),(b)更灵活,例如以标准ISO 8601以外的格式生成文本。

了解offset-from-UTC只是一小时,几分钟和几秒钟。而已。相比之下,time zone更多。时区是特定地区人民使用的偏移的过去,现在和将来变化的历史。例如,使用America/Los_Angeles时区的人们每年两次改变他们与UTC的偏差,这是一种愚蠢的做法,称为Daylight Saving Time (DST),从-08:00到-07:00再回来。

因此,通常时区优于仅仅偏移。例如,要看到你的Date,我们通过美国西海岸大多数人使用的挂钟时间变成了Instant,将时区America/Los_AngelesZoneId)应用到Instant以获得ZonedDateTime

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

你可以通过提取Instant回到UTC。

Instant instant = zdt.toInstant() ;

从那里回到java.util.Date(如果你必须,否则避免)。

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

†实际上,java.time.Date类确实有一个深埋在里面的时区。缺少任何访问器(获取/设置)方法,它是无法访问的。它的行为与我们在这里的讨论无关。混乱?是。避免可怕的遗留日期时间类的许多原因的另一个原因。

© www.soinside.com 2019 - 2024. All rights reserved.