我的Mageia 4中有欧洲/莫斯科时区。
像这样的代码
System.out.println(new java.util.Date());
System.out.println(System.getProperty("user.timezone"));
回报
Fri Oct 24 13:43:22 GMT+03:00 2014
GMT+03:00
如果我在24.10.2014设置系统日期
并且该代码返回
Sun Oct 26 14:44:26 GMT+03:00 2014
GMT+03:00
如果我在2014年10月26日设置系统日期
在我看来,这是java zoneinfo系统的错误行为。我下载了tzupdater并运行它,文件Europe / Moscow已更新,现在它的大小为705 kB。
我尝试下面的代码:
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Moscow"));
System.out.println(new java.util.Date());
System.out.println(java.util.TimeZone.getDefault());
然后它回来了
Fri Oct 24 15:10:34 MSK 2014
sun.util.calendar.ZoneInfo[id="Europe/Moscow",offset=10800000,dstSavings=0,useDaylight=false,transitions=79,lastRule=null]
和
Sun Oct 26 15:32:03 MSK 2014
sun.util.calendar.ZoneInfo[id="Europe/Moscow",offset=10800000,dstSavings=0,useDaylight=false,transitions=79,lastRule=null]
为什么这样?为什么在这两种情况下偏移是相同的?
+03:00
)(Europe/Moscow
)java.util.Date
。在UTC中,请使用java.time.Instant
。
Instant.now()
在某个时区,请使用java.time.ZonedDateTime
。
ZonedDateTime.now(
ZoneId.of( "Europe/Moscow" )
)
正如Jon Skeet的评论所指出的,你的JVM的初始默认时区不是time zone,它只是一个offset-from-UTC。
有什么不同?偏移量只是小时数,分钟数和秒数,正数(在UTC之前)或负数(在UTC之后)。时区要多得多。时区是特定地区人民使用的偏移的过去,现在和将来变化的历史。只要政客们如此认为,一个地区的抵消就会发生变化。例如,许多政客买入Daylight Saving Time (DST)的疯狂,并且每年两次改变抵消。
因此,如果您将时区设置为+03:00
(比UTC / GMT提前三个小时)而不是像Europe/Moscow
这样的时区,您的当前日期时间将始终报告为比UTC早三个小时。您所在地区的偏移量变化(如DST)将被忽略,因为您这样说,您说“始终比UTC早三个小时”。
您正在使用几年前由JSR 310中定义的java.time类取代的可怕日期时间类。
而不是TimeZone
,使用ZoneId
。
ZoneId z = ZoneId.of( "Europe/Moscow" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ; // Capture the current moment as seen in the wall-clock time used by the people of a particular region (a time zone).
您应该只将JVM的默认时区设置为最后的绝望行为。
设置默认时区(以及默认语言环境)会立即影响该JVM中运行的所有应用程序的所有线程中的所有代码。你将粗暴地改变其他程序员背后的区域。在运行时,您甚至可能会发现他们的代码会改变背后的区域。
最好将所有日期时间处理编写为永远不要依赖当前的默认区域(或语言环境)。通过传递可选参数明确指定所需/预期时区。就个人而言,我希望那些时区参数是必需的而不是可选的,以帮助受过教育的程序员关于日期时间问题。
我们可以在上面的代码中看到这样的例子。请注意我们如何将俄罗斯的ZoneId
传递给now
方法。否则,我们将捕获当前任何区域恰好是JVM当前默认时区的挂钟时间。
提示:如果严重,请始终与用户确认时区。
java.util.Date::toString
lies请注意,您调用的toString
对象上的Date
方法具有动态应用JVM当前默认时区的反功能,同时生成表示该时刻的文本。出于善意,这个不幸的设计决定让无数程序员试图在Java中纠缠日期时间值。 java.util.Date
实际上是UTC,是UTC自1970年第一个时刻以来的毫秒数。字符串中显示的时区实际上不在Date
对象中。
但这没有实际意义,因为这是完全避免这门课程的众多原因之一。请改用java.util.Instant
。而不是GregorianCalendar
,使用ZonedDateTime
。
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,如java.util.Date
,Calendar
和SimpleDateFormat
。
要了解更多信息,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规格是JSR 310。
现在在Joda-Time的maintenance mode项目建议迁移到java.time班。
您可以直接与数据库交换java.time对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*
类。
从哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展了java.time。该项目是未来可能添加到java.time的试验场。你可能会在这里找到一些有用的类,如Interval
,YearWeek
,YearQuarter
和more。
通过添加正确时区的定义解决了该问题。
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Moscow"));
你的第二次测试(26.10.2014)是在冬季变化之后所以你可能需要更正时间-1小时