使用Java8,我们知道useZoneId.default()
可以获取系统默认值ZoneId
,但是如何获取默认值ZoneOffset
呢?
我看到aZoneId
有一些“规则”,而每个规则都有a ZoneOffset
,这是否意味着aZoneId
可能有多个ZoneOffset
?
使用Java8,我们知道useZoneId.default()
可以获取系统默认值ZoneId
,但是如何获取默认值ZoneOffset
呢?
我看到aZoneId
有一些“规则”,而每个规则都有a ZoneOffset
,这是否意味着aZoneId
可能有多个ZoneOffset
?
ZoneOffset.systemDefault()
ZoneId
虽然会传回。
ZoneOffset current = zone.getRules().getOffset(instant)
Answers:
OffsetDateTime.now().getOffset()
但是您可能应该使用时区,而不是仅仅使用UTC偏移量。
ZoneId.systemDefault()
与UTC的偏移量仅是小时,分钟和秒的数量,仅此而已。例如,-08:00
表示比UTC晚八小时,+05:45
表示比UTC早五小时四十五分钟。
一个时区是过去,现在和未来的偏移量变化的历史使用由特定地区的人们。随着时间的过去,过去以及将来的政客宣布计划中的变更,都将跟踪诸如夏令时(DST)之类的异常,这些异常会导致偏移在特定时间段内的偏移。
因此最好在知道时使用区域。
任何区域的偏移量都会随时间变化。例如,美国的DST将偏移量偏移一个小时约半年,然后在该年的下半年将该小时恢复到偏移量。时区的全部目的是记录偏移的那些偏移。
因此,要求没有日期时间的偏移量确实没有任何意义。在中America/Los_Angeles
,例如,在今年的一部分中,偏移量是DST,-08:00
但是在另一部分中,则是-07:00
DST。
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
ZoneId
作为由yanys的评论所说,你可以询问一个ZoneId
特定ZoneOffset
通过传递一个时刻作为Instant
。该Instant
级表示时间轴上的时刻UTC,分辨率为纳秒(最多小数的9个位数)。
这只是到达同一目的地的另一条路线。就像用OffsetDateTime
和ZonedDateTime
上面所讨论的,我们指定(一)一个时区,以及(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 8和更高版本。这些类取代麻烦的老传统日期时间类,如java.util.Date
,Calendar
,和SimpleDateFormat
。
要了解更多信息,请参见Oracle教程。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
您可以直接与数据库交换java.time对象。使用与JDBC 4.2或更高版本兼容的JDBC驱动程序。不需要字符串,不需要类。Hibernate 5和JPA 2.2支持java.time。java.sql.*
在哪里获取java.time类?
+03:00
)之前一小时永久性地调整偏移量。政客经常做出这样的改变,而往往没有引起注意。这使得人们争先恐后地更新其区域定义的计算机“ tzdata”数据库列表。
zone.getRules().getOffset(instant)
,您需要手动将任何其他异常添加到获取的偏移量中,例如DST。偏移量返回的getOffset(instant)
已经是小时,分钟的确切数字和秒从格林尼治时间偏移那个瞬间的时间。(我一直认为偏移量只是地理偏移量,它描述了该区域太阳升起/
根据您的目标,您可能可以完全绕开ZoneOffset
。
假设您只需要一个ZoneOffset
for,例如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
。
ZoneOffset.systemDefault()