【问题标题】:Java programs in Linux Machine (UTC timezone) returning date in HDT timezone instead of UTC timezone [duplicate]Linux机器(UTC时区)中的Java程序以HDT时区而不是UTC时区返回日期[重复]
【发布时间】:2019-10-28 11:24:02
【问题描述】:

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

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

运行cat /etc/localtime 似乎也表明我的机器处于UTC 时区;

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

但是,在 Java 1.7 下运行 tomcat 的应用程序中调用 logger.info(new Date()) 会返回类似于 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 实用程序以 UTC 格式返回日期,而我的 Java 应用程序却以 HDT 格式返回日期(我什至不知道 HDT 是什么)。

由于我维护的应用是旧版应用,因此我无法使用 Joda Time 或升级到 Java8 或更高版本,因为这意味着要进行大量代码更改。

【问题讨论】:

  • /etc/timezone 说什么?见Check TimeZone on Linux host
  • HDT 代表 夏威夷夏令时间....机器是否位于(或按原样设置)在夏威夷?
  • @Sterconium 机器在公司数据中心,机器必须是UTC
  • 好的,但这不能回答我的问题:这台机器(或按原样设置)在夏威夷吗?
  • 老式的Date 没有时区。但它打印为HDT 表明JVM 的时区设置可能是夏威夷-阿留申时间。您可以通过打印ZoneId.systemDefault()System.getProperty("user.timezone")来查看。

标签: java linux date timezone java-7


【解决方案1】:

tl;博士

永远不要使用遗留类Date

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

2020-02-18T05:28:11.146726Z

2020-02-17T19:28:11.146726-10:00[太平洋/檀香山]

详情

首先,您应该知道您的java.util.Date 实际上是UTC 中的一个时刻,但它的toString 方法会在生成文本时动态应用JVM 的当前默认时区。非常混乱。 从不使用此类的众多原因之一。

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

避免依赖默认时区

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

UTC

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

Instant instant = Instant.now() ;

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

String output = instant.toString() ;

输出: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[太平洋/檀香山]



关于java.time

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

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

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

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

从哪里获得 java.time 类?

【讨论】:

    【解决方案2】:

    我最终通过以下方式修复它:

    • 运行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的想法

    【讨论】:

      猜你喜欢
      • 2013-06-16
      • 1970-01-01
      • 2020-02-06
      • 2020-12-17
      • 2019-06-05
      • 2023-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多