如何在 Java8中获得默认的 ZoneOffset?

在 Java8中,我们知道使用 ZoneId.default()可以得到系统默认的 ZoneId,但是如何得到默认的 ZoneOffset呢?

我看到一个 ZoneId有一些“规则”,每个规则有一个 ZoneOffset,这是否意味着一个 ZoneId可能有一个以上的 ZoneOffset

114117 次浏览

博士

OffsetDateTime.now().getOffset()

但是您可能应该使用一个时区,而不是仅仅使用与 UTC 的偏移量。

ZoneId.systemDefault()

Offset versus Time Zone

从协调世界时偏移仅仅是一个小时、分钟和秒的数字,仅此而已。例如,-08:00表示比 UTC 晚8小时,而 +05:45表示比 协调世界时早5小时45分钟。

时区是指一个特定地区的人们使用的 历史的过去,现在和未来的变化抵消。像 Daylight Saving Time (DST)这样的异常引起的偏移在特定的时间段内随着时间的推移而变化,在过去发生的时候,以及在未来政治家宣布计划的变化时都会被跟踪。

所以当我们知道 最好使用区域的时候。

任何区域的偏移量随时间变化。例如,DST in the United States在大约半年的时间里将偏移量偏移一个小时,然后在另一半时间里将该小时恢复到偏移量。时区的全部用途就是记录这些偏移。

所以它真的是 没有日期时间要求补偿是没有意义的。在 America/Los_Angeles,例如,在今年的一部分,抵消是 -08:00,但在另一部分的一年是 -07:00在 DST。

OffsetDateTime

因此,让我们指定一个时刻为 OffsetDateTime,然后提取 ZoneOffset

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

ToString () : 2017-01-02T15:19:47.162-08:00

ToString () : -08:00

这个 now方法实际上隐式地应用了 JVM 当前的默认时区。我建议你总是通过指定你想要的/期望的时区来明确这一点。即使你想要当前的默认区域,也要明确地说明你的意图。消除关于是否打算使用默认设置还是没有像程序员经常遇到的那样考虑时区的模糊性。打电话给 ZoneId.systemDefault

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

SystemDefault () . toString () : America/Los _ Angeles

Odt: 2017-01-02 T15:19:47.162-08:00

ZoneOffsetOfOdt: -08:00

关于依赖默认区域的警告: JVM 中任何线程的任何代码都可以随时更改此默认区域。如果非常重要,询问用户他们想要的时区。

您可以要求偏移量的时间量作为总秒数。

int offsetSeconds = zoneOffset.getTotalSeconds ();

秒数: -28800

ZonedDateTime

另一个例子: 也许你想知道今年魁北克的圣诞节会有什么抵消。指定时区 America/Montreal,得到一个 ZonedDateTime,请求它作为 ZoneOffset对象的偏移量。

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

ToString () : 2017-12-25T00:00-05:00[美国/蒙特利尔]

ToString () : -05:00

GetTotalSecds () : -18000

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

ZoneId

正如 yanys 在评论中建议的那样,您可以通过传递一个作为 Instant的时刻来询问特定 ZoneOffsetZoneIdInstant类代表 协调世界时时间线上的一个时刻,其分辨率为 纳秒(小数分数的9位数)。

这只是通往同一目的地的另一条路线。就像上面讨论的 OffsetDateTimeZonedDateTime一样,我们指定了(a)一个时区和(b)一个时刻。

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

对于 ZoneId: 美国/蒙特利尔即时: 2017-12-25 T05:00:00Z ZoneOffset 是: -05:00

参见所有这些例子的 代码在 IdeOne.com 上直播

缺陷或功能?

The ZoneOffset class, a subclass of ZoneId, is documented as inheriting the systemDefault method. However, this does not actually work.

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

error: incompatible types: ZoneId cannot be converted to ZoneOffset

不确定这个编译失败是一个 bug 还是一个特性。正如上面所讨论的,对我来说要求使用日期时间的默认偏移量似乎没有意义,所以也许 ZoneOffset.systemDefault确实应该失败。但是文件应该这么说,并附上解释。

我试图归档一个错误的文件未能解决这个问题,但放弃了,无法确定在哪里和如何提交这样的错误报告。

太阳时与政治时

更多关于偏移和时区的内容。

Solar Time has been used since pre-history, tracking each day by noting when the sun is directly overhead. Poke a stick in the ground, and watch its shadow. When the shadow is shortest, when the shadow begins to grow rather than shrink, then you know it is now noon. Formalize that with a 日晷 to track the hours pass.

随着太阳时间的推移,当你从一个城镇向西移动到另一个城镇时,中午的到来会稍微晚一点。向东移动,中午来得稍微早一点。因此,每个城镇都有自己的中午,只与沿着同一经度的南北两个城镇分享。

Solar time was largely abandoned in the modern era. As trains, telegraphs, and telephones arrived, so did the need to coordinate temporally. So a point was picked for its near solar time of noon, and a large swath of land so many miles to the west and to the east is declared to all share the same 12:00 on the clock, the 在格林尼治本初子午线之前或之后相同的时间偏移. So began the tradition of every train stop displaying prominently a clock to let the town know of the 标准时间 for their larger region rather than solar time for their own town. Generally, towns in the western edge of that time zone region will see their train station clock read 12:00 a little 之前 the sun is overhead. Clocks in towns in the eastern edge of the region read 12:00 a little 之后 the sun is overhead.

世界各地的政治家们表现出了改变其管辖权的抵消方式的倾向。原因是多方面的,如外交,战争和占领,以及 夏时制的愚蠢。原因各不相同,但它们的变化频率惊人。时区是指一个区域的名称,用于跟踪该区域此类更改的历史记录。所以一个 < a href = “//en.wikipedia.org/wiki/UTC _ offrer”rel = “ noreference rer”> 偏离-from-UTC 仅仅是几个小时-分钟-秒在本初子午线的前面或后面。对特定区域的偏移量的过去、现在和未来变化的 时区更重要的是: 一段历史。虽然两个邻近地区今天可能共享相同的抵消从协调世界时,在过去或未来,他们可能会有所不同,这取决于不同的突发奇想或政治家的逻辑。

这意味着由政治家定义的现代时间跟踪与地理位置几乎没有关系。例如,印度这个巨大的国家今天只有一个时区(与世界协调时偏移 + 05:30)。所以太阳中午(太阳直射你的头顶)在广阔的次大陆的各个地方相隔几个小时。印度的政治家们决定这样做是为了帮助统一他们多元化的民主政体。在世界各地的其他例子中,我们看到一些地区将他们的时区作为国际关系的象征,比如与其冒犯的邻国不同,或者选择与邻国相同的时区作为解冻的关系,最近在朝鲜看到的是朝韩关系的变化。所以,现在,太阳时只是时间跟踪的几个考虑因素之一。


About 爪哇时间

The < em > java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

要了解更多,请参阅 < em > Oracle 教程 。并搜索堆栈溢出许多例子和解释。规范是 JSR 310

现在在 维修模式中的 尤达时间项目建议迁移到 爪哇时间类。

您可以直接与数据库交换 爪哇时间对象。使用与 JDBC 4.2或更高版本兼容的 JDBC 驱动程序。不需要字符串,不需要 java.sql.*类。Hibernate 5 & JPA 2.2支持 爪哇时间

从哪里获得 java.time 类?

Table of which java.time library to use with which version of Java or Android

根据你的目标,你可能能够 完全绕过 ZoneOffset

Assuming you just need a ZoneOffset for e.g. LocalDateTime.ofEpochSecond(), you may replace

ZoneOffset offset = OffsetDateTime.now().getOffset();
LocalDateTime dt1 = LocalDateTime.ofEpochSecond(seconds, 0, offset);

LocalDateTime dt2 = LocalDateTime.ofInstant(
Instant.ofEpochSecond(seconds),
ZoneId.systemDefault());

其中 dt1.equals(dt2)true