Java中的时区不匹配

时间:2013-10-26 06:29:44

标签: java

我在美国的Ubuntu Server中运行了一个Java应用程序并配置了CEST时区。

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

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

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

它让我回到了EDT的时间。我错过了什么配置。

3 个答案:

答案 0 :(得分:2)

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

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

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

-Duser.timezone="America/New_York" 

答案 1 :(得分:0)

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

答案 2 :(得分:0)

TL;博士

UTC:

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➞总是

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

Instant.now().toString()
  

2018-03-16T00:57:34.233762Z

该字符串格式为标准ISO 8601格式。最后的ZZulu的缩写,表示UTC

  

CEST区域时间

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

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 Server中运行了一个Java应用程序并配置了CEST时区

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

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

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

(顺便说一句,Locale同上 - 始终指定所需/期望的语言环境,而不是隐含地依赖当前默认语言。)

关于 java.time

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

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

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

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

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore