我的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”那样的时区。
我对如何处理这个问题感到有些困惑。
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
有一个时区,实际上它没有†。
其次,你将非常好的现代java.time类(OffsetDateTime
)与非常可怕的遗留日期时间类(Date
)混合在一起。不要这样做。完全避免遗留类。它们在2014年被JSR 310采用后被淘汰。
如果交了一个java.util.Date
对象,立即转换为java.time。调用添加到旧类的新转换方法。 Instant
类直接替换Date
,作为UTC的一个时刻,但具有更精细的分辨率纳秒与毫秒。
Instant instant = myJavaUtilDate.toInstant() ; // Convert from legacy class to modern class.
您通常应该跟踪UTC中的时刻。您可以将此作为Instant
或OffsetDateTime
,其偏移量设置为ZoneOffset.UTC
常量。
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ; // Same moment, no change in meaning whatsoever.
特别是对于UTC,我们的代码中的instant
和odt
之间没有区别。它们都代表了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_Angeles
(ZoneId
)应用到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
类确实有一个深埋在里面的时区。缺少任何访问器(获取/设置)方法,它是无法访问的。它的行为与我们在这里的讨论无关。混乱?是。避免可怕的遗留日期时间类的许多原因的另一个原因。