首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >java zoneinfo有什么问题?

java zoneinfo有什么问题?
EN

Stack Overflow用户
提问于 2014-10-31 12:00:36
回答 3查看 5.8K关注 0票数 3

我的Mageia 4号有欧洲/莫斯科时区。

像这样的代码

代码语言:javascript
复制
System.out.println(new java.util.Date());
System.out.println(System.getProperty("user.timezone"));

返回

代码语言:javascript
复制
Fri Oct 24 13:43:22 GMT+03:00 2014
GMT+03:00

如果我将系统日期设置在2014年10月24日

而代码返回

代码语言:javascript
复制
Sun Oct 26 14:44:26 GMT+03:00 2014
GMT+03:00

如果我将系统日期设置为26.10.2014

在我看来,这是java zoneinfo系统的错误行为。我下载了tzupdater并运行它,更新了欧洲/莫斯科的文件,现在它的大小是705 kB。

我尝试下面的代码:

代码语言:javascript
复制
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Moscow"));
                System.out.println(new java.util.Date());
                System.out.println(java.util.TimeZone.getDefault());

然后它又回来了

代码语言:javascript
复制
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]

代码语言:javascript
复制
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]

为什么会这样呢?为什么这两种情况下的抵消是相同的?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-03-14 00:29:35

tl;dr

  • 当您指时区(+03:00)时,不要使用偏移量(Europe/Moscow)
  • 永远不要依赖JVM当前的默认时区。
  • 永远不要使用java.util.Date

在UTC的某个时刻,使用java.time.Instant

代码语言:javascript
复制
Instant.now()

在时区的某个时刻,使用java.time.ZonedDateTime

代码语言:javascript
复制
ZonedDateTime.now(
    ZoneId.of( "Europe/Moscow" ) 
)

偏移量与时区

正如Jon的评论所指出的,JVM最初的默认时区不是时区,它只是一个与世界协调时相抵

有什么关系?偏移量只是指数小时、分钟和秒数、正(高于UTC)或负(UTC后面)。时区更重要。时区是过去、现在和未来对某一特定地区人民使用的偏移量变化的历史。一个地区的补偿可以在政客们认为的时候改变。例如,许多政客相信夏令时(DST)的疯狂行为,并且每年两次改变这种抵消。

因此,如果您将时区设置为仅为+03:00 (比UTC /格林尼治时间提前3小时)这样的偏移量,而不是像Europe/Moscow这样的时区,则您当前的日期时间总是比UTC提前3小时。您的地区的偏移量更改(如DST )将被忽略,因为您这样说,您说“总是比UTC提前三个小时”。

java.time

您正在使用几年前被JSR 310中定义的java.time类取代的糟糕的日期时间类。

不要使用TimeZone,而是使用ZoneId

代码语言:javascript
复制
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谎言

请注意,您正在调用的toString对象上的Date方法具有一个反特性,即动态应用JVM当前的默认时区,同时生成表示该时刻的文本。尽管用意良好,但这个不幸的设计决策让无数试图在Java中争论日期-时间值的程序员感到困惑。一个java.util.Date实际上是以UTC为单位的,从1970年世界协调时的第一个时刻算起就是毫秒数。字符串中显示的时区实际上不在Date对象中。

但是这是没有意义的,因为这是完全避免这个类的许多原因之一。使用java.util.Instant代替。不要使用GregorianCalendar,而是使用ZonedDateTime

关于java.time

http://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html框架内置到Java8和更高版本中。这些类取代了麻烦的旧遗赠日期时间类,如java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参见http://docs.oracle.com/javase/tutorial/datetime/TOC.html。并搜索堆栈溢出以获得许多示例和解释。规范是JSR 310

http://www.joda.org/joda-time/项目现在在维护模式中,建议迁移到java.time类。

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

在哪里获得java.time类?

  • Java 8Java 9Java 10Java 11和更高版本--捆绑实现的标准Java的一部分。
    • Java 9添加了一些次要的特性和修复。

  • Java 6Java 7
    • 大多数java.time功能都是在http://www.threeten.org/threetenbp/中移植到Java6&7中的。

  • 安卓
    • 较晚版本的Android实现的java.time类。
    • 对于早期的Android (<26),https://github.com/JakeWharton/ThreeTenABP项目采用了http://www.threeten.org/threetenbp/ (上面提到的)。见http://stackoverflow.com/q/38922754/642706

三次-额外项目使用其他类扩展java.time。这个项目是将来可能加入java.time的试验场。您可以在这里找到一些有用的类,如IntervalYearWeekYearQuarter更多

票数 5
EN

Stack Overflow用户

发布于 2014-10-31 17:30:11

通过增加正确时区的定义,解决了这个问题。

代码语言:javascript
复制
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Moscow"));
票数 2
EN

Stack Overflow用户

发布于 2014-10-31 12:16:56

您的第二次测试(26.10.2014)是在更改到冬季之后,因此您可能还需要在-1小时内更正时间。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26674248

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档