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