Java时间与操作系统时间不同

标签 java datetime

当我在 Unix 中打印日期时,它显示 UTC 时间

[app@host ~]$ date
Thu Sep  6 21:16:07 UTC 2018

当我在同一台机器上从 Java 打印日期时
public static void main(String[] args) {
  System.out.println("date=" + new Date());
  System.out.println("date from mills=" + new Date(System.currentTimeMillis()));
  System.out.println(TimeZone.getDefault().getDisplayName());

  Instant instant = Instant.now();
  System.out.println("instant=" + instant);
  System.out.println("instant from mills=" + new Date(instant.toEpochMilli()));
}

它打印 PST 时间
[app@host ~]$ java TimeTest
date=Thu Sep 06 14:17:09 PDT 2018
date from mills=Thu Sep 06 14:17:09 PDT 2018
Pacific Standard Time
instant=2018-09-06T21:17:09.030Z
instant from mills=Thu Sep 06 14:17:09 PDT 2018

Java 如何获取 PST 时区?

此外,logback 文件轮换发生在 UTC 时间,并且日志文件中打印的时间显示 PST 时间。

最佳答案

tl;博士

仅使用 java.time 类。

永远不要使用 Date 类。

记录时使用UTC。

Instant.now().toString()

2018-01-23T01:23:45.123456Z



细节

这已经在 Stack Overflow 上多次解决了。

糟糕的旧式日期时间类充斥着糟糕的设计选择。在这些糟糕的选择中,Date::toString 方法在生成字符串时动态应用 JVM 的当前默认时区的行为。出于好意但具有误导性,因为 java.util.Date ,如 java.time.Instant ,代表UTC 中的一个时刻。

今年 9 月 6 日,北美大部分地区西海岸的下午 2 点在 UTC 时间同时为晚上 9 点,在夏令时 (DST) 期间,UTC 比 UTC 晚了 7 小时。同一时刻,时间线上的同一点,不同的挂钟时间。

为什么是 PDT?

为什么是 PDT,特别是太平洋夏令时?您的 JVM 始终具有当前的默认时区。显然,您的 JVM 设置为区域的当前默认值,例如 America/Los_Angeles(PDT 不是实时时区)。

如何设置默认值取决于您的 JVM 实现和您的设置。通常启动时的 JVM 会选择主机操作系统的当前默认区域。您可以将参数传递给 JVM 的启动以指定区域而不是选择主机操作系统的默认值。

启动后,JVM 中任何应用程序的任何线程中的任何代码都可以随时通过调用 TimeZone.setDefault 更改当前默认时区,以立即影响该 JVM 中的所有其他代码。

这意味着您永远不应该依赖当前默认区域来处理任何重要的事情,因为它的值超出了您作为程序员的控制范围。始终明确指定您想要/预期的时区。即使您想使用当前默认值,也请显式调用 ZoneId.systemDefault

额外提示: Locale 也是如此。始终为当前默认值。但是明确指定而不是隐式依赖默认值。

使用 java.time

永远不要使用旧的日期类。仅使用 java.time 类。

记录时,始终使用 UTC。以标准 ISO 8601 格式呈现文本,如 Instant::toString 中所示。
Instant instant = Instant.now() ;

如果您想查看特定地区人民使用的挂钟时间中的那一刻,请应用时区 ( ZoneId ) 以获取 ZonedDateTime
ZoneId z = ZoneId.of( "America/Los_Angeles" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

关于 java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date Calendar SimpleDateFormat

Joda-Time 项目,现在在 maintenance mode 中,建议迁移到 java.time 类。

要了解更多信息,请参阅 Oracle Tutorial 。并在 Stack Overflow 上搜索许多示例和解释。规范是 JSR 310

您可以直接与您的数据库交换 java.time 对象。使用符合 JDBC driver 或更高版本的 JDBC 4.2。不需要字符串,不需要 java.sql.* 类。

从哪里获得 java.time 类?
  • Java SE 8Java SE 9Java SE 10Java SE 11 和更高版本 - 具有捆绑实现的标准 Java API 的一部分。
  • Java 9 添加了一些小功能和修复。
  • Java SE 6Java SE 7
  • 大多数 java.time 功能在 ThreeTen-Backport 中被反向移植到 Java 6 和 7。
  • Android
  • 更高版本的 Android 捆绑实现 java.time 类。
  • 对于早期的Android(<26),ThreeTenABP 项目适配了ThreeTen-Backport(上面提到过)。见 How to use ThreeTenABP…

  • ThreeTen-Extra 项目使用附加类扩展了 java.time。该项目是 future 可能添加到 java.time 的试验场。您可能会在这里找到一些有用的类,例如 Interval YearWeek YearQuarter more

    关于Java时间与操作系统时间不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52248114/

    相关文章:

    java - JSR 303 Bean Validation,验证在 XML 中定义数组值

    java - 我是否必须为每个 jsp 或 java 更改重新启动 tomcat?

    python - pandas如何忽略无法转换为日期时间以计算时间增量的列单元格

    python pandas从时间序列中提取唯一日期

    python - 如何更改 matplotlib 图的日期时间刻度标签频率

    java - 解释 tpm-tools tpm_getpubek 输出

    Java:调用/返回错误

    java - 没有绑定(bind) akka.actor.ActorRef 的实现

    datetime - Ecto.DateTime 和时区

    c# - 从某个字符串中检索 DateTime 对象