如何在java8中获取默认的ZoneOffset?

Fre*_*uvn 46 java timezone timezone-offset java-8

使用java8我们知道使用ZoneId.default()可以获得系统默认值ZoneId,但如何获取默认值ZoneOffset

我看到一个ZoneId有一些"规则",每个规则都有一个ZoneOffset,这意味着一个ZoneId可能有一个以上ZoneOffset吗?

Bas*_*que 129

TL;博士

OffsetDateTime.now().getOffset()
Run Code Online (Sandbox Code Playgroud)

偏移与时区

与UTC偏移仅仅是小时,分钟和秒的数量 - 仅此而已.

时区是偏移的针对特定区域中的历史加上一组规则来处理异常,如日光节约时间(DST) ,导致在时间的偏移量超过特定时间段的变化.

时区=(偏移历史+异常规则)

因此,在知道时更好地使用区域.

任何地区的偏移量随时间而变化.例如,美国的DST将偏移量移动一小时,大约一半,然后在一年的另一半时间内将该小时恢复到偏移量.时区的整个目的是记录偏移量的变化.

因此,在没有日期时间的情况下要求偏移是没有意义的.在-08:00,例如在今年的一部分偏移+05:45,但在今年的另一部分是America/Los_AngelesDST期间.

-08:00

所以让我们指定一个时刻作为-07:00,然后提取OffsetDateTime.

ZoneId.systemDefault() 
Run Code Online (Sandbox Code Playgroud)

odt.toString():2017-01-02T15:19:47.162-08:00

zoneOffset.toString(): - 08:00

OffsetDateTime方法实际上是隐式应用JVM的当前默认时区.我建议您始终通过指定所需/预期的时区来明确说明.即使您想要当前的默认区域,也要明确说明您的意图.消除关于您是否打算默认或未能考虑时区的模糊性,因为程序员经常会这样做.打电话ZoneOffset.

OffsetDateTime odt = OffsetDateTime.now ();
ZoneOffset zoneOffset = odt.getOffset ();
Run Code Online (Sandbox Code Playgroud)

ZoneId.systemDefault().toString():America/Los_Angeles

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

zoneOffsetOfOdt:-08:00

关于依赖于默认区域的注意事项:此默认值可随时由JVM中任何线程中的任何代码更改.如果重要,请询问用户预期的时区.

您可以将偏移量作为总秒数询问偏移量.

OffsetDateTime odt = OffsetDateTime.now ( ZoneId.systemDefault () );
ZoneOffset zoneOffset = odt.getOffset ();
Run Code Online (Sandbox Code Playgroud)

offsetSeconds:-28800

now

另一个例子:也许你想知道今年圣诞节在魁北克会有什么补偿.指定时区ZoneId.systemDefault,获取a ZonedDateTime,询问其偏移量作为America/Montreal对象.

int offsetSeconds = zoneOffset.getTotalSeconds ();
Run Code Online (Sandbox Code Playgroud)

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

zoneOffsetXmas.toString(): - 05:00

zoneOffsetXmas.getTotalSeconds(): - 18000

ZonedDateTime

正如yanys的评论中所建议的那样,你可以通过传递一个时刻来查询ZoneOffset一个特定ZoneId的东西ZoneId.该ZoneOffset级表示时间轴上的时刻UTC,分辨率为纳秒(最多9个(9)小数的位数).

这只是通往同一目的地的另一条路线.就像用InstantInstant上面所讨论的,我们指定(一)一个时区,以及(b)一个时刻.

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

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

在IdeOne.com上查看所有这些示例的代码.

OffsetDateTime - 错误或功能?

ZonedDateTime类,的一个子类ZoneOffset.systemDefault,被记录为继承ZoneOffset方法.但是,这实际上并不起作用.

Instant instant = zdtXmas.toInstant();
ZoneOffset zo = z.getRules().getOffset( instant );
Run Code Online (Sandbox Code Playgroud)

错误:不兼容的类型:ZoneId无法转换为ZoneOffset

不确定这个编译失败是错误还是功能.如上所述,对我来说似乎没有理由要求默认偏移量与日期时间,所以也许ZoneId应该确实失败.但文档应该这样说,并附上解释.

我试图提交一个关于文档无法解决此问题的错误,但放弃了,无法确定在何处以及如何提交此类错误报告.


关于java.time

java.time框架是建立在Java 8和更高版本.这些类取代麻烦的老传统日期时间类,如systemDefault,ZoneOffset.systemDefault,和java.util.Date.

现在处于维护模式Joda-Time项目建议迁移到java.time类.

要了解更多信息,请参阅Oracle教程.并搜索Stack Overflow以获取许多示例和解释.规范是JSR 310.

您可以直接与数据库交换java.time对象.使用符合JDBC 4.2或更高版本的JDBC驱动程序.不需要字符串,不需要课程.Calendar

从哪里获取java.time类?

ThreeTen-额外项目与其他类扩展java.time.该项目是未来可能添加到java.time的试验场.您可以在此比如找到一些有用的类SimpleDateFormat,java.sql.*,Interval,和更多.

  • @FredSuvn 这就是夏令时(DST)的定义,半年一个偏移,半年另一个偏移。而且夏令时并不是唯一的原因;其他异常会导致特定时区的偏移量发生变化。例如,2016 年秋季,[土耳其决定永久调整其偏移一小时](https://www.timeanddate.com/news/time/turkey-scraps-dst-2016.html) 进一步提前 UTC (`+ 03:00`)。政客们经常做出这样的改变,而且往往很少有人注意到。这使得人们争先恐后地更新计算机的“tzdata”数据库区域定义列表。 (2认同)
  • 很长一段时间以来我在 SO 上看到的最佳答案@FredSuvn 您应该通过单击 ✅ 来接受答案 (2认同)