Java Linux 机器(UTC 时区)中的程序以 HDT 时区而不是 UTC 时区返回日期

Java programs in Linux Machine (UTC timezone) returning date in HDT timezone instead of UTC timezone

我在 UTC 时区有一台 linux 机器。

[user@test packages]$ date +'%:z %Z'
+00:00 UTC

运行 cat /etc/localtime 好像也说明我的机器是UTC时区;

[user@test ~]$ cat /etc/localtime
f2UTCTZif2UTC
UTC0

但是在应用程序中调用 logger.info(new Date()) 运行ning tomcat under Java 1.7 returns 类似于 Mon Oct 28 01:51:39 HDT 2019

这很奇怪,所以我创建了一个简单的 Java 程序进行测试:

import java.util.Date;

class Test
{
        public static void main (String args[])
        {
                Date dt = new Date();
                System.out.println(dt);
        }
}

编译并运行它

[user@test]$ /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.211.x86_64/bin/javac Test.java
[user@test]$ /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.211.x86_64/bin/java Test
Mon Oct 28 02:08:49 HDT 2019

我的问题是为什么我的 Linux 实用程序是 return UTC 格式的日期,而我的 Java 应用程序是 return HDT 格式的日期(我不知道甚至不知道 HDT 是什么)。

由于我正在维护的应用程序是遗留的,我不能使用 Joda Time 或升级到 Java8 或更高版本,因为这意味着大量代码更改。

我最终通过执行以下操作修复了它:

  • 运行 ln -fs /usr/share/zoneinfo/UTC /etc/timezone
  • 修改/etc/sysconfig/clock

读完这个 https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6456628

我有了看 /etc/sysconfig/clock 的想法

tl;博士

切勿使用旧版 class Date

  • Instant.now()
    以 UTC 显示的当前时刻。
  • ZonedDateTime.now( ZoneId.of( "Pacific/Honolulu" ) )
    对于在特定时区看到的当前时刻。

2020-02-18T05:28:11.146726Z

2020-02-17T19:28:11.146726-10:00[Pacific/Honolulu]

详情

首先,您应该知道您的 java.util.Date 实际上是 UTC 时间,但它的 toString 方法在生成文本时动态应用 JVM 当前的默认时区。非常混乱。 从不使用此 class.

的众多原因之一

DateCalendar 和其他遗留日期时间 classes 在几年前被 java.time 取代随着 JSR 310 的采用。

根据默认时区避免

使用 java.time classes,您可以轻松编写不依赖于默认时区的代码。您可以明确指定所需的 UTC 偏移量或时区,无论是 UTC 本身(零小时-分钟-秒的偏移量)还是 time zone like Pacific/Honolulu

UTC

如果您想在 UTC 中跟踪某个时刻,请使用 Instant

Instant instant = Instant.now() ;

Instant::toString 方法生成标准 ISO 8601 格式的文本。此标准定义的格式专为数据交换而设计。

String output = instant.toString() ;

output: 2020-02-18T05:28:11.146726Z

最后的Z表示UTC,发音为“Zulu”。

分区

如果您想按照夏威夷人使用的挂钟时间查看同一时刻,请应用 ZoneId 以获得 ZonedDateTime

切勿使用 2-4 个字母的缩写,例如 HDTESTIST,因为它们 不是 真实时区,不是标准化的,甚至不是唯一的(!)。

Continent/Region的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland

ZoneId z = ZoneId.of( "Pacific/Honolulu" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

ZonedDateTime::toString 方法通过附加时区名称方括号明智地扩展了 ISO 8601 格式。

String output = zdt.toString() ;

看到这个code run live at IdeOne.com

outputZdt: 2020-02-17T19:28:11.146726-10:00[Pacific/Honolulu]



关于java.time

java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

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

从哪里获得java.time classes?