在Java中使用OffsetDateTime处理夏令时,无论DST如何,本地时间都需要保持不变

在Java中使用OffsetDateTime处理夏令时,无论DST如何,本地时间都需要保持不变,java,spring,spring-boot,dst,offsetdatetime,Java,Spring,Spring Boot,Dst,Offsetdatetime,我正在使用SpringBoot(Java8)为一个餐馆应用程序开发后端,该应用程序公开了一些RESTAPI。所有与日期和时间相关的内容都通过OffsetDateTime对象处理,默认情况下,我通过应用程序使用“Europe/Rome”的偏移量。这些对象也在数据库中持久化。一切正常,除了。。。夏令时开始了,现在餐厅的所有营业时间都缩短了一个小时 这显然是因为在DST前,“欧洲/罗马”的偏移量为+01:00,而DST后的偏移量为+02:00。因此,举个例子,餐厅的营业时间(保存在DB pre DST

我正在使用SpringBoot(Java8)为一个餐馆应用程序开发后端,该应用程序公开了一些RESTAPI。所有与日期和时间相关的内容都通过
OffsetDateTime
对象处理,默认情况下,我通过应用程序使用
“Europe/Rome”
的偏移量。这些对象也在数据库中持久化。一切正常,除了。。。夏令时开始了,现在餐厅的所有营业时间都缩短了一个小时

这显然是因为在DST前,“欧洲/罗马”的偏移量为
+01:00
,而DST后的偏移量为
+02:00
。因此,举个例子,餐厅的营业时间(保存在DB pre DST中)是
08:30:00+01:00
,但从API访问post DST时它会变成
09:30:00+02:00
(因为它会自动转换为系统的默认区域)。我需要餐厅的营业时间在当地时间保持不变,无论DST如何

如何处理这种情况并向用户提供一致的数据?

偏移量与时区
“欧洲/罗马”
是时区的名称,而不是偏移量

与UTC的偏移量只是UTC基准线之前或之后的小时分秒数。当您向东移动时,当地时间比UTC早越来越多的小时,而向西移动到美洲时,当地时间比UTC晚越来越多的小时

时区更重要。时区是特定地区人民使用的偏移量的过去、现在和未来变化的历史

大陆/地区
的格式指定,例如
美国/蒙特利尔
非洲/卡萨布兰卡
,或
太平洋/奥克兰
。切勿使用2-4个字母的缩写,如
EST
IST
,因为它们不是真正的时区,也不是标准化的,甚至不是唯一的(!)

你说:

与日期和时间相关的所有内容都使用
OffsetDateTime
对象进行处理

不,您不应该在所有情况下使用单个类
OffsetDateTime
类用于表示知道偏移但不知道时区的时刻<当您知道时区时,应使用code>zoneDateTime。对于UTC(零偏移量)中的特定时刻,通常最好使用
Instant

Instant momentWhenRestaurantActuallyOpened = Instant.now() ;  // 09:41 AM, eleven minutes late because the manager could not find the door keys that had dropped to the floor.
OffsetDateTime
类很少是正确的选择。时区总是比单纯的偏移更可取。因此,通常您需要
ZonedDateTime
Instant
。一般来说,程序员和系统管理员应该在UTC中思考、工作、记录和调试,因此要使用
Instant
。要在预期时区或业务规则要求的地方向用户演示,请使用
zoneDateTime
。一个大的例外是数据库访问的工作-莫名其妙地要求compliant支持
OffsetDateTime
,但不支持
Instant
ZoneDateTime
。幸运的是,类之间的转换非常简单和容易

瞬间 你需要理解片刻与非片刻之间的区别。一个时刻是时间线上的一个特定点。忘了时区和补偿吧,如果摩洛哥卡萨布兰卡的人给日本东京的人打电话,他们就在同一时刻。要跟踪某个时刻,请使用上面以蓝色方框显示的三个类中的一个:
Instant
OffsetDateTime
zoneDateTime

Instant phoneCallStartedUtc=Instant.now();//UTC中的一个时刻。
ZonedDateTime PhoneCallStarted卡萨布兰卡=phoneCallStartedUtc.atZone(ZoneId.of(“非洲/卡萨布兰卡”);
ZonedDateTime phoneCallStartedTokyo=phoneCallStartedUtc.atZone(ZoneId.of(“亚洲/东京”);
看这个

phoneCallStartedUtc.toString():2021-03-28620:33:58.695669Z
电话呼叫StartedCasablanca.toString():2021-03-28221:33:58.695669+01:00[非洲/卡萨布兰卡]
电话呼叫StartedTokyo.toString():2021-03-29T05:33:58.695669+09:00[亚洲/东京]
所有这三个对象,
phoneCallStartedUtc
phoneCallStartedCasablanca
phoneCallStartedTokyo
,都代表着非常相同的同时时刻。他们唯一的区别是通过不同的挂钟时间(人们抬头看墙上的钟时看到的时间)观看

一刻也不 未来的约会,例如餐厅何时开业,或者患者下次看牙医的时间,不能立即跟踪

我们可能知道餐厅开业的日期和时间,但我们不知道具体时间。这是因为时区中使用的时钟时间是由政治家定义的

世界各地的政治家都表现出了改变其辖区时区时钟定义规则的倾向。它们日以继夜地作为一种政治声明,以区别于相邻司法管辖区,或相反,与邻国保持一致。政客们改变了他们的区域规则,使之成为现实。他们在战争和占领期间移动时钟是出于象征和后勤原因。当政客们加入时尚时,他们会改变时间,比如。后来,当他们加入一个不同的时尚时,他们会再次移动他们的时钟,比如全年都呆在DST上

这里要吸取的教训是,时区规则会发生变化,它们的变化频率惊人,而且变化很小甚至很小。因此,例如,下周二下午3点实际上可能不会发生在你现在预计的周三。没人知道,下一个下午3点可能比现在预计的早一个小时,比现在预计的晚半个小时

要跟踪时钟跟踪的未来约会,如餐厅开业,请使用<