Java中的时区不匹配

Java中的时区不匹配,java,Java,我在美国的Ubuntu服务器上运行了一个Java应用程序,并配置了CEST时区 若我在终端中运行Date命令,它将返回CEST时区的日期—这是完美的 但是在Java中,如果我运行以下代码 System.out.println (new Date ()); 它以EDT返回我的时间。我缺少什么配置。您说服务器配置为在CEST时区,但根据Java,默认时区是EDT。Java从操作系统获取默认时区,因此您的服务器可能未正确设置为CEST 如果要打印特定时区中的日期,请使用DateFormat并在其上设

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

若我在终端中运行Date命令,它将返回CEST时区的日期—这是完美的

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

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

它以EDT返回我的时间。我缺少什么配置。

您说服务器配置为在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将在适当的情况下自动在夏季显示时间)。

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

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

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

-Duser.timezone="America/New_York" 
太长,读不下去了 UTC:

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[非洲/突尼斯]

细节 这一点是正确的

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

java.util.Date
的替换为
java.time.Instant
。该类表示时间轴上的一个时刻,分辨率为(最多九(9)位小数)

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

Instant.now().toString()
2018-03-16T00:57:34.233762Z

字符串格式是标准格式。末尾的
Z
Zulu
的缩写,意思是

CEST区时间

没有名为
CEST
的时区。这是伪时区。它们不是标准化的。它们不是唯一的(!),而是以
大陆/地区的格式使用

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[欧洲/巴黎]

或者使用快捷方式

您也可以将一个
ZoneDateTime
调整到另一个时区。请注意java.time使用了。因此,在调整过程中,我们会在原始时区的基础上获得一个新的不同对象,但不会干扰原始时区

ZoneId zNewYork = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdtNewYork = zdt.withZoneSameInstant( zNewYork ) ;
zdtNewYork.toString():2018-03-15T20:57:34.233762-04:00[美国/纽约]

非常清楚的是,
instant
zdt
zdtNewYork
是三个独立的对象,它们表示非常相同的时刻,时间线上的相同点。相同的时刻,不同的挂钟时间

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

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

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

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

(顺便说一下,
Locale
——始终指定所需/预期的语言环境,而不是隐式地依赖当前默认设置。)


关于java.time 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,如,&

该项目现已启动,建议迁移到类

要了解更多信息,请参阅.和搜索堆栈溢出以获取许多示例和解释。规范为

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

从哪里获得java.time类

  • ,及以后
    • 内置的
    • 标准JavaAPI的一部分,带有捆绑实现
    • Java9添加了一些次要功能和修复
    • 大部分java.time功能都在中向后移植到Java6和Java7
    • 更高版本的Android捆绑包实现了java.time类
    • 对于早期的Android(参见
      ZonedDateTime zdt = ZonedDateTime.now( z ) ;
      
      ZoneId zNewYork = ZoneId.of( "America/New_York" ) ;
      ZonedDateTime zdtNewYork = zdt.withZoneSameInstant( zNewYork ) ;