tl;博士
使用 UTC
将UTC 视为“真正的时间”。特定时区的任何日期时间都是 UTC 的派生。在进行编程或系统管理工作时,请忘记您自己的本地时区。我强烈建议在您的物理桌面和数字桌面上都添加一个时钟以显示 UTC。在紧要关头,使用Time.is 等网站。
您的大部分业务逻辑、日志记录、数据存储、数据交换和数据库持久性都应该使用 UTC。调整为仅用于演示的时区。
避免使用旧的日期时间类
避免与最早版本的 Java 捆绑在一起的麻烦的旧的旧日期时间类。现在被 java.time 类所取代。
Instant
Instant 类代表UTC 中时间轴上的一个时刻,分辨率为nanoseconds。
Instant now = Instant.now(); // Current moment in UTC.
指定时区
Java 虚拟机有一个当前的默认时区。这可以在从主机操作系统启动时获取。或者它可以在启动时通过配置设置进行设置。或者它可能随时被 JVM 中任何应用程序的任何线程中的任何代码更改——在执行期间影响所有其他代码!
鉴于 JVM 当前的默认时区不同,并且超出了程序员的控制范围,因此永远不要依赖它。 始终指定您希望/预期的时区。
通常最好将服务器主机操作系统设置为 UTC 时区,但同样,在您的编程中永远不要依赖它。
ZonedDateTime
要将Instant 调整为时区,请生成ZonedDateTime 对象。
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
调用toString 以生成标准ISO 8601 格式的字符串。对于其他格式,请在 Stack Overflow 中搜索 DateTimeFormatter 类。
更新您的 tz 时区数据库
时区定义及其异常情况(例如Daylight Saving Time (DST))经常变化,出奇地频繁。
Oracle 定期发布 Java 更新,其中包括 tz database 的新副本。如果您无法安装这些 Java 更新,或者如果一些粗心的政客在最后一刻对区域进行了更改,您可以使用 Oracle 的 Timezone Updater Tool 手动更新您的 Java。
Locale
知道Locale 与时区无关。 Locale 定义 (a) 用于翻译的人类语言,以及 (b) 决定诸如缩写、标点符号和部分顺序等问题的文化规范。所以在生成字符串时只需要一个Locale,当使用DateTimeFormatter类时。
Locale l = Locale.CANADA_FRENCH;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( l );
String output = zdt.format( f );
所以时区定义了日期时间值的含义,而Locale 定义了它的表示。
关于java.time
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧日期时间类,例如java.util.Date、.Calendar 和java.text.SimpleDateFormat。
Joda-Time 项目现在位于maintenance mode,建议迁移到 java.time。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。
大部分 java.time 功能在ThreeTen-Backport 中向后移植到Java 6 和7,并进一步适应ThreeTenABP 中的Android(参见How to use…)。
ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如Interval、YearWeek、YearQuarter 等等。