操作系统无关
您的操作系统配置是无关紧要的。大多数Java实现在启动时默认从主机操作系统中选择其初始默认时区。但是,时区的定义存储在Java实现内部。
Java时区更新程序
因此,您需要更新Java实现中的时区定义。大多数实现使用tz数据库,也称为tzdata。
对于Oracle品牌的Java实现,Oracle提供Timezone Updater Tool。该页面的截止日期为2018-08,因此可能已包含您所在时区的更改。但我建议您进行更详细的调查以进行验证。
对于其他实现,请与供应商联系。他们可能已经提供了包含新tzdata的JVM的更新版本。或者他们也提供更新程序工具。或者您可以手动替换tzdata文件。
避免使用代码混淆区域
我强烈建议您避免尝试在代码中自行进行人为调整。您很可能会出错。日期时间工作令人惊讶地棘手和令人困惑。
但如果你坚持使用日期时间类,首先避免可怕的旧遗留日期时间类,例如
GregorianCalendar
&
Calendar
&
Date
。多年前,它们已被JSR 310所取代。如果你必须与尚未更新为
java.time的旧代码进行交互,请在现代类中完成工作,然后最后通过添加到旧类的新方法进行转换。
使用现代的
java.time类,具体包括:
Instant
(UTC中的某一时刻)
OffsetDateTime
(带有时区偏移量的某一时刻,但没有时区)
ZonedDateTime
(特定时区中的某一时刻)
你可以在Stack Overflow上搜索许多使用这些类的现有示例和解释。你应该专注于
OffsetDateTime
,
ZoneOffset
(而不是
ZoneId
),以及
Instant
,因为如果你知道你的
tzdata文件已过时,则必须避免使用
ZonedDateTime
。
同一时刻,不同的挂钟时间
![enter image description here](https://istack.dev59.com/EDEAg.webp)
OffsetDateTime::withOffsetSameInstant
OffsetDateTime odt = OffsetDateTime.parse( "2018-10-21T01:00:00.000-02:00" ) ;
ZoneOffset offset = ZoneOffset.ofHours( -3 ) ;
OffsetDateTime odt2 = odt.withOffsetSameInstant( offset ) ; // Same moment, same point on the timeline, different wall-clock time.
在这个例子中,
odt
和
odt2
都代表同一时刻,时间线上的同一点。如果你提取一个
Instant
(UTC值),你的结果将是相同的时刻。只有它们的挂钟时间不同。
Instant instant1 = odt.toInstant() ; // Adjust to UTC.
Instant instant2 = odt2.toInstant() ;
boolean sameMoment = instant1.equals( instant2 ) ;
instant1.toString(): 2018-10-21T03:00:00Z
instant2.toString(): 2018-10-21T03:00:00Z
sameMoment = true
“Z”代表UTC,偏移量为零,即+00:00。 “Z”发音为“Zulu”。由
ISO 8601标准定义。
相同的墙上时间,不同的时刻。
![enter image description here](https://istack.dev59.com/RwRKg.webp)
OffsetDateTime::withOffsetSameLocal
相比之下,您可能希望强制指定时间,并因此表示一个不同的时刻。为此,请使用withOffsetSameLocal
方法。请非常注意,您正在改变数据的含义,您正在移动到时间线上的另一点。
OffsetDateTime differentMomentButSameTimeOfDay = odt. withOffsetSameLocal( offset ) ;
不同的时刻,但时间相同:2018-10-21T01:00-03:00。提取瞬间以查看我们是否有不同的时刻。
Instant differentInstant = differentMomentButSameTimeOfDay.toInstant() ;
differentInstant.toString(): 2018-10-21T04:00:00Z
注意上面看到的UTC时间4点和3点之间的差异。这一刻发生在上面那一刻的一个小时后,是时间轴上的两个不同点。
在完全理解时间轴上的点和改变点之间的转换与调整偏移量之间的完全不同之前,请勿尝试此工作。在进行真正的工作之前,请进行广泛的实践。半心半意的猜测只会让你陷入困境和头痛之中。
而且,正如我上面建议的那样,你最好花时间安装更新的tzdata文件,而不是修改这些偏移量。
实时代码
查看上面所有代码
在IdeOne.com上运行。
更新各地的tzdata
为了获得最佳效果,您应该在以下所有各种地方更新tzdata(或等效物):
- 操作系统
- JVM
- 数据库引擎,例如
Postgres
- 任何捆绑自己的时区信息的库(例如:
Joda-Time)
关于java.time
java.time框架是Java 8及以上版本内置的。这些类取代了老旧的legacy日期时间类,如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类?
ThreeTen-Extra 项目使用额外的类扩展了 java.time。该项目是 java.time 可能未来添加内容的试验场。您可能会在这里找到一些有用的类,例如 Interval
、YearWeek
、YearQuarter
和more。