Java时间与OS时间不同 - java

当我在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时区?

同样,回传文件的轮换发生在UTC时间,并且日志文件中打印的时间显示了PST时间。

参考方案

tl; dr

仅使用java.time类。

切勿使用Date类。

记录时使用UTC。

Instant.now().toString()

2018-01-23T01:23:45.123456Z

细节

堆栈溢出已经解决了很多次。

糟糕的旧式传统日期时间类充斥着糟糕的设计选择。在这些较差的选择中,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.DateCalendarSimpleDateFormat

现在位于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
  • 更高版本的java.time类的Android捆绑实现。
  • 对于早期的Android(<26),ThreeTenABP项目改编了ThreeTen-Backport(如上所述)。参见How to use ThreeTenABP…
  • ThreeTen-Extra项目使用其他类扩展了java.time。该项目是将来可能向java.time添加内容的试验场。您可能会在这里找到一些有用的类,例如 IntervalYearWeekYearQuarter 和more。

    Java:正则表达式模式匹配器是否有大小限制? - java

    我的模式类似于OR:“word1 | word2 | word3”我大约有800个字。可能有问题吗? 参考方案 您仅受记忆和理智的限制。 :)

    Java:线程池如何将线程映射到可运行对象 - java

    试图绕过Java并发问题,并且很难理解线程池,线程以及它们正在执行的可运行“任务”之间的关系。如果我创建一个有10个线程的线程池,那么我是否必须将相同的任务传递给池中的每个线程,或者池化的线程实际上只是与任务无关的“工人无人机”可用于执行任何任务?无论哪种方式,Executor / ExecutorService如何将正确的任务分配给正确的线程? 参考方案 …

    JAVA:字节码和二进制有什么区别? - java

    java字节代码(已编译的语言,也称为目标代码)与机器代码(当前计算机的本机代码)之间有什么区别?我读过一些书,他们将字节码称为二进制指令,但我不知道为什么。 参考方案 字节码是独立于平台的,在Windows中运行的编译器编译的字节码仍将在linux / unix / mac中运行。机器代码是特定于平台的,如果在Windows x86中编译,则它将仅在Win…

    java:继承 - java

    有哪些替代继承的方法? java大神给出的解决方案 有效的Java:偏重于继承而不是继承。 (这实际上也来自“四人帮”)。他提出的理由是,如果扩展类未明确设计为继承,则继承会引起很多不正常的副作用。例如,对super.someMethod()的任何调用都可以引导您通过未知代码的意外路径。取而代之的是,持有对本来应该扩展的类的引用,然后委托给它。这是与Eric…

    Java:BigInteger,如何通过OutputStream编写它 - java

    我想将BigInteger写入文件。做这个的最好方式是什么。当然,我想从输入流中读取(使用程序,而不是人工)。我必须使用ObjectOutputStream还是有更好的方法?目的是使用尽可能少的字节。谢谢马丁 参考方案 Java序列化(ObjectOutputStream / ObjectInputStream)是将对象序列化为八位字节序列的一种通用方法。但…