【问题标题】:Time Zone mismatch in JavaJava中的时区不匹配
【发布时间】:2013-10-26 06:29:44
【问题描述】:

我在美国的 Ubuntu 服务器上运行了一个 Java 应用程序,并配置了 CEST 时区。

如果我在终端中运行 Date 命令,它会在 CEST 区域时间返回日期 - 这是完美的。

但在 Java 中,如果我运行以下代码

System.out.println (new Date ());

它会返回美国东部时间的时间。我缺少什么配置。

【问题讨论】:

标签: java


【解决方案1】:

您必须小心解释控制台中显示的日期对象,因为它们是使用运行此程序的 VM 的默认时区格式化的(默认情况下,它从操作系统的时区继承)。 当然,您可以按照 Jesper 的回答中的说明提供自己的 TimeZone。但在这样做的同时,我会强烈建议使用 IANA 时区标识符,例如 America/New_York 而不是 EST。更是如此,因为带有“标准”的缩写不考虑夏令时。

因此,如果您只是在控制台上打印日期对象并且没有得到预期的结果,则很有可能您的服务器时区设置为错误的值或您的操作系统设置为错误的时区。

要更改 JVM 时区,您可以在启动时使用此参数

-Duser.timezone="America/New_York" 

【讨论】:

    【解决方案2】:

    您说服务器配置为 CEST 时区,但根据 Java,默认时区是 EDT。 Java 从操作系统获取默认时区,因此您的服务器可能未正确设置为 CEST。

    如果您想在特定时区打印日期,请使用DateFormat 并在其上设置时区:

    DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
    df.setTimeZone(TimeZone.getTimeZone("CET"));
    System.out.println(df.format(new Date()));
    

    注意:根据我的 Java (Java 7u45),CEST 不是有效的时区。您指的是 “CET” 吗? (CEST 是 CET 的夏令时变体,但如果您使用 CET,Java 将在适当的情况下自动显示夏令时时间)。

    【讨论】:

      【解决方案3】:

      tl;博士

      世界标准时间:

      Instant.now()    // Instantiate an object capturing the current moment in UTC.
          .toString()  // Generate a String representing textually that date-time value using standard ISO 8601 format.
      

      2018-03-16T00:57:34.233762Z

      分区:

      ZonedDateTime.now( ZoneId.of( "Africa/Tunis" ) )  // Instantiate an object representing the current moment with a wall-clock time seed by people in a particular region (time zone). 
          .toString()                                   // Generate a String representing textually that date-time value using standard ISO 8601 format wisely extended to append the name of the time zone in square brackets. 
      

      2018-03-16T01:57:34.233762+01:00[非洲/突尼斯]

      详情

      Answer by Shailendra 准确无误。

      此外,问题中看到的Date 类是麻烦的旧日期时间类的一部分,这些类现在已成为遗留问题,完全被 java.time 类所取代。

      java.util.Date 的替换是 java.time.InstantInstant 类代表UTC 时间线上的时刻,分辨率为nanoseconds(最多九 (9) 位小数)。

      Instant::toString ➞ UTC 始终

      当调用遗留类的 Date::toString 方法时,其作者选择的不幸行为是动态应用 JVM 当前的默认时区。这不会造成混乱。幸运的是,现代类在没有添加任何时区的情况下说出了一个简单的事实:Instant 始终采用 UTC。

      Instant.now().toString()
      

      2018-03-16T00:57:34.233762Z

      字符串格式是标准的ISO 8601 格式。末尾的ZZulu 的缩写,意思是UTC

      CEST 时区时间

      不存在名为CEST 的时区。这样的3-4 letter names 是伪区域。它们没有标准化。它们不是唯一的(!)。而是使用proper time zone 格式为continent/region

      ZoneId z = ZoneId.of( "Europe/Paris" ) ;
      

      您可以通过将ZoneId 应用于您的Instant 来获得ZoneDateTime,从而将UTC 调整为这样的时区。

      Instant instant = Instant.now() ;
      ZonedDateTime zdt = instant.atZone( z ) ;
      

      zdt.toString(): 2018-03-16T01:57:34.233762+01:00[欧洲/巴黎]

      或使用快捷方式ZonedDateTime.now

      ZonedDateTime zdt = ZonedDateTime.now( z ) ;
      

      您也可以将ZonedDateTime 调整到另一个时区。注意 java.time 使用immutable objects。因此,在调整的过程中,我们得到了一个基于原始对象但又不干扰原始对象的新对象。

      ZoneId zNewYork = ZoneId.of( "America/New_York" ) ;
      ZonedDateTime zdtNewYork = zdt.withZoneSameInstant( zNewYork ) ;
      

      zdtNewYork.toString(): 2018-03-15T20:57:34.233762-04:00[America/New_York]

      非常清楚instantzdtzdtNewYork 是三个独立的对象,它们代表同一时刻,即时间轴上的同一点。同一时刻,不同的挂钟时间。

      我在美国的 Ubuntu 服务器上运行了一个 Java 应用程序并配置了 CEST 时区

      仅供参考,一般来说,服务器默认时区的最佳做法是 UTC。

      更重要的是,您的服务器操作系统和 JVM 的当前默认时区应该与您的 Java 应用程序无关。

      与其隐式依赖 JVM 当前的默认时区,不如始终明确指定所需/预期的时区。将可选的 ZoneId 参数传递给各种 java.time 方法,如上面的代码所示。

      (顺便说一句,Locale 也是如此 - 始终指定所需/预期的语言环境,而不是隐式依赖当前默认值。)


      关于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 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

      从哪里获得 java.time 类?

      • Java SE 8Java SE 9 及更高版本
        • 内置。
        • 标准 Java API 的一部分,带有捆绑实现。
        • Java 9 添加了一些小功能和修复。
      • Java SE 6Java SE 7
        • 大部分 java.time 功能都在ThreeTen-Backport 中向后移植到 Java 6 和 7。
      • Android
        • 更高版本的 Android 捆绑包实现 java.time 类。
        • 对于早期的 Android (ThreeTenABP 项目采用 ThreeTen-Backport(如上所述)。见How to use ThreeTenABP…

      ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

      【讨论】:

        猜你喜欢
        • 2020-10-01
        • 1970-01-01
        • 1970-01-01
        • 2015-03-17
        • 2020-02-16
        • 2015-06-05
        • 2013-10-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多