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


77

使用Java8,我们知道useZoneId.default()可以获取系统默认值ZoneId,但是如何获取默认值ZoneOffset呢?

我看到aZoneId有一些“规则”,而每个规则都有a ZoneOffset,这是否意味着aZoneId可能有多个ZoneOffset


试试ZoneOffset.systemDefault()
Shubham Chaurasia

2
由于夏令时,许多时区都有不同的偏移量。
马克·菲利普

15
ZoneOffset.systemDefault()ZoneId虽然会传回。
马克·菲利普

3
当前ZoneOffset是ZoneId和Instant的函数。ZoneOffset current = zone.getRules().getOffset(instant)
Alexander Yanyshin

3
@FredSuvn我相信yanys明白了这样的概念:在没有指定时区和时间(日期时间值)的情况下,要求补偿是没有意义的。例如:夏令时进入America/Los_Angeles导致偏移-08:00当前,但-07:00在夏天更改为。因此,您不能不说何时生效以及在哪个时区要求补偿。请参阅我的答案以获取更多讨论。
罗勒·布尔克

Answers:


178

tl; dr

OffsetDateTime.now().getOffset()

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

ZoneId.systemDefault() 

偏移量与时区

与UTC偏移量仅是小时,分钟和秒的数量,仅此而已。例如,-08:00表示比UTC晚八小时,+05:45表示比UTC早五小时四十五分钟。

一个时区过去,现在和未来的偏移量变化的历史使用由特定地区的人们。随着时间的过去,过去以及将来的政客宣布计划中的变更,都将跟踪诸如夏令时(DST)之类的异常,这些异常会导致偏移在特定时间段内的偏移。

因此最好在知道时使用区域

任何区域的偏移量都会随时间变化。例如,美国的DST将偏移量偏移一个小时约半年,然后在该年的下半年将该小时恢复到偏移量。时区的全部目的是记录偏移的那些偏移。

因此,要求没有日期时间的偏移量确实没有任何意义。在中America/Los_Angeles,例如,在今年的一部分中,偏移量是DST,-08:00但是在另一部分中,则是-07:00DST。

OffsetDateTime

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

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

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

zoneOffset.toString():-08:00

now方法实际上隐式地应用了JVM的当前默认时区。我建议您始终通过指定所需/预期的时区来使之明确。即使您想要当前的默认区域,也要明确地说出您的意图。消除关于程序员是默认的还是默认的时区的不确定性。致电ZoneId.systemDefault

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

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

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

zoneOffsetOfOdt:-08:00

关于取决于默认区域的警告:可以随时通过JVM中任何线程中的任何代码来更改此默认值。如果重要,请询问用户其预期的时区。

您可以要求偏移量的时间,以秒为单位。

int offsetSeconds = zoneOffset.getTotalSeconds ();

offsetSecond:-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();

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

zoneOffsetXmas.toString():-05:00

zoneOffsetXmas.getTotalSeconds():-18000

Java中的日期时间类型表,包括现代的和传统的。

ZoneId

作为由yanys的评论所说,你可以询问一个ZoneId特定ZoneOffset通过传递一个时刻作为Instant。该Instant级表示时间轴上的时刻UTC,分辨率为纳秒(最多小数的9个位数)。

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

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

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

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

ZoneOffset.systemDefault –错误或功能?

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

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

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

不确定此编译失败是错误还是功能。如上所述,对我而言,要求使用日期时间作为默认偏移量似乎没有任何意义,因此也许ZoneOffset.systemDefault应该确实失败了。但是文档应该这样说,并附有解释。

我试图针对文档未能解决此问题提交错误,但我放弃了,无法确定在何处以及如何提交此类错误报告。

太阳时间与政治时间

有关偏移量和时区的更多信息...

从史前开始就使用“太阳时间”,通过记录太阳何时直接在头顶上方来跟踪每天。在地面上戳一根棍子,并观察其阴影。当阴影最短时,当阴影开始增长而不是缩小时,您就会知道现在是中午。使用日d对小时进行正式化处理。

随着太阳时间的推移,当您从一个城镇向另一个城镇移动时,中午又到了一点。向东移动,中午更快到达。因此,每个城镇都有自己的正午,仅与北部和南部沿相同经度的城镇共享。

在现代时代,太阳时间基本上被遗弃了。随着火车,电报和电话的到来,临时协调的需求也随之而来。因此,在接近中午的太阳时选择了一个时间点,并且宣布了一个向西和向东如此多英里的大片土地,它们在时钟上共享相同的12:00,并且向前偏移相同的小时数或后面格林威治本初子午线线。这样一来,每列火车停靠的传统都显眼地显示了一个时钟,以便让城镇知道其较大地区的标准时间,而不是自己城镇的太阳能时间。通常,该时区区域西部边缘的城镇会在稍早12:00之前看到火车站的时钟太阳在头顶。太阳升起后不久,该地区东部边缘城镇的时钟读数为12:00 。

世界各地的政客都对改变其管辖权的偏移表现出了浓厚的兴趣。原因各不相同,例如外交,战争和占领以及夏令时(DST)的愚蠢。原因各不相同,但变化的频率令人惊讶。时区是赋予区域以跟踪其变化历史的名称。因此,与UTC偏移量在本初子午线之前或之后数小时-数分钟-秒。一个时区得多:一个历史的过去,现在和未来的一个特定区域的偏移量的变化。尽管今天两个相邻地区可能共享相同的UTC偏移量,但在过去或将来,它们可能会根据其政客的异想天开或逻辑而有所不同。

这意味着政治家定义的现代时间跟踪与地理关系不大。例如,今天印度这个大国有一个时区(UTC与+05:30的偏移量)。因此,在整个次大陆的各个地方,太阳正午(太阳直射在您头顶)相隔数小时。印度政客们决定这样做是为了帮助统一其多元化的民主。在世界各地的其他示例中,我们看到各地区将时区用作国际关系的象征,例如与其所在的邻国不同,或者在关系解冻时选择与邻国相同的时区,如最近在朝鲜发生变化以匹配韩国。因此,如今,太阳时间只是时间跟踪中的几个考虑因素之一。


关于java.time

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

要了解更多信息,请参见Oracle教程。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

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

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

在哪里获取java.time类?

哪个版本的Java或Android使用哪个java.time库的表


您的意思是偏移量的值在一个区域的不同时间是不同的?多谢!
FredSuvn

1
@FredSuvn这就是夏令时(DST)的定义,一年偏移一半,另一年偏移一半。DST不是唯一原因。其他异常会导致特定时区的偏移量发生变化。例如,在2016年秋天,土耳其决定在世界标准时间+03:00)之前一小时永久性地调整偏移量。政客经常做出这样的改变,而往往没有引起注意。这使得人们争先恐后地更新其区域定义的计算机“ tzdata”数据库列表。
罗勒·布尔克

我已经在SO上看到了最好的答案seen @FredSuvn您应该通过单击accept接受答案
earcam '17

对于被方程式Time Zone =(偏移量历史+异常规则)迷惑的其他人。这并不意味着使用时zone.getRules().getOffset(instant),您需要手动将任何其他异常添加到获取的偏移量中,例如DST。偏移量返回的getOffset(instant)已经是小时,分钟的确切数字和秒从格林尼治时间偏移那个瞬间的时间。(我一直认为偏移量只是地理偏移量,它描述了该区域太阳升起/
降落多少

@anddero您的评论促使我删除了该等式,并添加了有关太阳时间与政治时间的部分。希望现在阅读得更清楚。
罗勒·布尔克

0

根据您的目标,您可能可以完全绕开ZoneOffset

假设您只需要一个ZoneOffsetfor,例如LocalDateTime.ofEpochSecond(),您可以替换

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.