在Java 8中,我们知道可以使用ZoneId.default()
获取系统默认的ZoneId
,但是如何获取默认的ZoneOffset
呢?
我看到一个ZoneId
有一些“规则”,每个规则都有一个ZoneOffset
,这是否意味着一个ZoneId
可能拥有多个ZoneOffset
?
在Java 8中,我们知道可以使用ZoneId.default()
获取系统默认的ZoneId
,但是如何获取默认的ZoneOffset
呢?
我看到一个ZoneId
有一些“规则”,每个规则都有一个ZoneOffset
,这是否意味着一个ZoneId
可能拥有多个ZoneOffset
?
OffsetDateTime.now().getOffset()
但你应该使用时区而不是简单的与协调世界时的偏移量。
ZoneId.systemDefault()
一个偏移量(距离协调世界时)只是一个小时、分钟和秒数的数字,没有其他含义。例如,-08:00
表示比协调世界时晚八小时,+05:45
表示比协调世界时提前五小时四十五分钟。
一个时区是一个特定地区人民过去、现在和未来偏移量变化的历史记录。诸如夏令时(DST)等异常情况会导致偏移量在特定时间段内发生改变,并且这些变化被追踪记录,包括过去的变化以及政府官员公布计划变更的未来变化。
因此,当已知时最好使用时区。
任何地区的偏移量随时间而变化。例如,美国的夏令时在一年中的大约一半时间将偏移量提前一个小时,然后在另一半时间将这个小时重新加回到偏移量中。时区的整个目的就是记录这些偏移量的变化。OffsetDateTime odt = OffsetDateTime.now ();
ZoneOffset zoneOffset = odt.getOffset ();
ZoneId.systemDefault
。OffsetDateTime odt = OffsetDateTime.now ( ZoneId.systemDefault () );
ZoneOffset zoneOffset = odt.getOffset ();
int offsetSeconds = zoneOffset.getTotalSeconds ();
另一个例子:也许你想知道今年圣诞节在魁北克的偏移量是多少。指定时区为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();
ZoneId
如yanys的评论所建议,您可以通过将时间作为Instant
传递给ZoneId
来查询特定ZoneOffset
。Instant
类表示UTC上的时间点,其分辨率为纳秒(最多九位小数)。
这只是达到相同目标的另一种方法。就像上面讨论的OffsetDateTime
和ZonedDateTime
一样,我们指定了(a)时区和(b)时间点。
Instant instant = zdtXmas.toInstant();
ZoneOffset zo = z.getRules().getOffset( instant );
ZoneOffset.systemDefault
ZoneOffset
类是ZoneId
的子类,继承了systemDefault
方法。然而,我们不能使用该方法来确定当前的偏移量。继承的方法返回的是超类ZoneId
的对象,而不是子类ZoneOffset
的对象。ZoneOffset zoneOffset = ZoneOffset.systemDefault() ; // Error.
// Fails to compile.
// Every ZoneOffset is a ZoneId, but not every ZoneId is a ZoneOffset.
// We cannot assign a superclass object to a reference variable of the subclass type.
ZoneId zoneId = ZoneId.systemDefault ( );
ZoneRules rules = zoneId.getRules ( );
Instant
对象,即以零小时-分钟-秒的偏移量从UTC看到的日期和时间。Instant now = Instant.now ( );
ZoneOffset offset = rules.getOffset ( now );
System.out.println ( "For zone " + zoneId + " at " + now + ", the offset is " + offset );
世界各地的政治家们表现出一种改变其管辖范围偏移量的倾向。原因各不相同,比如外交、战争和占领,以及夏令时的荒谬之处。这些原因各不相同,但他们的改变频率让人惊讶。时区是一个名称,用来追踪该地区的历史变化。因此,“与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驱动程序。无需字符串,无需java.sql.*
类。Hibernate 5和JPA 2.2支持java.time。
如何获取java.time类?
+03:00
)。政治家经常做出这样的改变,通常很少提前通知。这让人们匆忙更新计算机的“tzdata”数据库列表中的区域定义。 - Basil Bourquezone.getRules().getOffset(instant)
时,需要手动添加任何其他异常情况到获取的偏移量中,例如夏令时。**getOffset(instant)
返回的偏移量已经是该时间点与 GMT 的确切小时、分钟和秒数偏移量。**(我一直以为偏移量只是地理偏移量,描述了该地区太阳升起的早晚程度,但实际上它考虑了所有规则。) - Snackoverflow根据您的目标,您可能能够完全绕过ZoneOffset
。
假设您只需要一个ZoneOffset
用于例如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()
。 - Shubham ChaurasiaZoneOffset.systemDefault()
返回的是ZoneId
。 - Marc PhilippZoneOffset current = zone.getRules().getOffset(instant)
。 - Alexander Yanyshin