tl;dr
- 不要使用偏移量 (
+03:00
)当您指的是时区(Europe/Moscow
)
- 切勿依赖 JVM 当前的默认时区。
- 切勿使用
java.util.Date
.
在 UTC 中,使用java.time.Instant
.
Instant.now()
对于某个时区的某个时刻,请使用java.time.ZonedDateTime
.
ZonedDateTime.now(
ZoneId.of( "Europe/Moscow" )
)
偏移量与时区
正如 Jon Skeet 的评论所指出的,您的 JVM 的初始默认时区不是一个时区 https://en.wikipedia.org/wiki/Time_zone,这只是一个与 UTC 的偏移量 https://en.wikipedia.org/wiki/UTC_offset.
有什么不同?偏移量只是小时数、分钟数和秒数,正数(早于 UTC)或负数(晚于 UTC)。时区是much更多的。时区是特定地区的人们使用的偏移量的过去、现在和未来变化的历史。只要政治家认为,某个地区的抵消额就可以改变。例如,许多政客相信了夏令时 (DST) https://en.wikipedia.org/wiki/Daylight_saving_time,并每年更改两次偏移量。
因此,如果您将时区设置为纯粹的偏移量,例如+03:00
(比 UTC/GMT 早三个小时)而不是时区,例如Europe/Moscow
,您当前的日期时间将始终报告为比 UTC 早三个小时。您所在地区的偏移量变化(例如 DST)将被忽略,因为您是这么说的,您说过“始终比 UTC 早三个小时”。
java.time
您正在使用可怕的日期时间类,这些类在几年前就被java.timeJSR 310 中定义的类。
代替TimeZone
, use ZoneId
.
ZoneId z = ZoneId.of( "Europe/Moscow" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ; // Capture the current moment as seen in the wall-clock time used by the people of a particular region (a time zone).
避免设置默认时区
您只应将 JVM 设置为默认时区作为最后的绝望之举。
设置默认时区(顺便说一句,还有默认区域设置)会立即影响该 JVM 中运行的所有应用程序的所有线程中的所有代码。你会在其他程序员背后粗鲁地改变区域。您甚至可能会发现他们的代码更改了后面的区域your back, during运行。
最好编写所有日期时间处理,不要依赖当前的默认区域(或区域设置)。通过传递可选参数明确指定您想要/预期的时区。就我个人而言,我希望这些时区参数是必需的而不是可选的,以帮助受过教育的程序员解决日期时间问题。
我们可以在上面的代码中看到一个例子。注意我们如何通过ZoneId
对于俄罗斯来说now
方法。否则,我们将捕获恰好是 JVM 当前默认时区的任何区域的挂钟时间中的当前时刻。
提示:如果很重要,请务必与用户确认时区。
java.util.Date::toString
lies
请注意,toString
方法上的Date
您调用的对象具有动态应用 JVM 当前默认时区的反功能,同时生成表示该时刻的文本。尽管本意是好的,但这种不幸的设计决策却让无数试图在 Java 中争论日期时间值的程序员感到困惑。 Ajava.util.Date
实际上采用 UTC 格式,是自 UTC 1970 年第一个时刻以来的毫秒数。字符串中显示的时区实际上并不在Date
目的。
但这是没有意义的,因为这是其中之一many完全避免此类的原因。使用java.util.Instant
反而。代替GregorianCalendar
, use ZonedDateTime
.
About java.time
The java.time http://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html框架内置于 Java 8 及更高版本中。这些课程取代了麻烦的旧课程legacy https://en.wikipedia.org/wiki/Legacy_system日期时间类,例如java.util.Date https://docs.oracle.com/javase/10/docs/api/java/util/Date.html, Calendar https://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html, & SimpleDateFormat http://docs.oracle.com/javase/10/docs/api/java/text/SimpleDateFormat.html.
要了解更多信息,请参阅甲骨文教程 http://docs.oracle.com/javase/tutorial/datetime/TOC.html。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310 https://jcp.org/en/jsr/detail?id=310.
The 乔达时间 http://www.joda.org/joda-time/项目,现在在维护模式 https://en.wikipedia.org/wiki/Maintenance_mode,建议迁移到java.time http://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html类。
您可以交换java.time对象直接与您的数据库。用一个JDBC驱动程序 https://en.wikipedia.org/wiki/JDBC_driver符合JDBC 4.2 http://openjdk.java.net/jeps/170或稍后。不需要字符串,不需要java.sql.*
类。
从哪里获取 java.time 类?
-
Java SE 8 https://en.wikipedia.org/wiki/Java_version_history#Java_SE_8, Java SE 9 https://en.wikipedia.org/wiki/Java_version_history#Java_SE_9, Java SE 10 https://en.wikipedia.org/wiki/Java_version_history#Java_SE_10, Java SE 11 https://en.wikipedia.org/wiki/Java_version_history#Java_SE_11, and later - Part of the standard Java API with a bundled implementation.
-
Java SE 6 https://en.wikipedia.org/wiki/Java_version_history#Java_SE_6 and Java SE 7 https://en.wikipedia.org/wiki/Java_version_history#Java_SE_7
- 大部分的java.time功能向后移植到 Java 6 和 7三十后端口 http://www.threeten.org/threetenbp/.
-
Android https://en.wikipedia.org/wiki/Android_(operating_system)
- 更高版本的 Android 捆绑实现java.time类。
- 对于早期的 Android (三十ABP项目适应三十后端口 http://www.threeten.org/threetenbp/(上文提到的)。看如何使用 ThreeTenABP... http://stackoverflow.com/q/38922754/642706.
The 三十额外 http://www.threeten.org/threeten-extra/项目通过附加类扩展了 java.time。该项目是 java.time 未来可能添加的内容的试验场。您可能会在这里找到一些有用的类,例如Interval http://www.threeten.org/threeten-extra/apidocs/org/threeten/extra/Interval.html, YearWeek http://www.threeten.org/threeten-extra/apidocs/org/threeten/extra/YearWeek.html, YearQuarter http://www.threeten.org/threeten-extra/apidocs/org/threeten/extra/YearQuarter.html, and more http://www.threeten.org/threeten-extra/apidocs/index.html.