【问题标题】:Java time one hour behindJava 时间落后一小时
【发布时间】:2011-05-04 01:25:44
【问题描述】:

我有一个严重依赖 Java 的应用程序。我们进行了大量的日志记录、数据库插入等。在白天的时间切换之后,我们注意到所有 Java 时间都落后了大约一个小时。我们有 1.6_18 的 Jre 版本。我认为这个问题在早期版本的 Java 中得到了解决。如果有任何补丁,请建议可以做什么。

【问题讨论】:

  • 您能否发布导致您意外结果的代码部分?在这一点上只是一个猜测,但可能是您的默认日期/时间设置为错误的时区,或者设置为不识别夏令时,或其他一些小事。
  • 您的应用程序使用什么语言环境?
  • @Synesso - 是的,这就是我的意思。 :)
  • 糟糕,我的意思是说时区,而不是语言环境。 ;)
  • 最好在UTC而不是任何一个时区进行日志记录和跟踪。时区和夏令时 (DST) 经常被修改。此外,JVM 内任何应用程序的任何线程中的任何代码都可以更改当前的默认时区。致电 Instant.now() 以获取 UTC 的当前时刻。

标签: time java


【解决方案1】:

时区信息会定期修改。 Java 6 更新 18 可能包含您所在位置的过时 DST 设置。

升级到最新版本 (update 25) 或运行 TZupdater 工具。

编辑:我刚刚发现 Oracle 提供了一个RSS feed for timezone updates。如果您的应用程序绝对必须拥有最新的 TZ 数据,请留意这一点。

【讨论】:

  • 这适用于东部标准时间的机器,设置多久更改一次?
  • Java 6 update 18 有 Olsen TZ 数据 2009s。 Java 6 更新 25 具有 Olsen TZ 数据 2011b。差异显示在此页面上:oracle.com/technetwork/java/javase/tzdata-versions-138805.html 我在该差异中没有看到任何专门针对您的时区的内容,但请尝试一下,它可能会有所帮助。
  • 另一件需要考虑的事情:您可能合理地假设您的应用程序在特定时区运行,但您的假设可能是错误的。在运行时自省 java.util.TimeZone.getDefault().getID() 绝对确定。
  • 根据 Timezone Updater Tool 页面“每次执行都会修改 JDK/JRE 软件的单个映像。” (oracle.com/technetwork/java/javase/tzupdater-readme-136440.html) 有关于如何在同一系统上的多个 JRE 之间应用 tz 更新的说明。 (为了安全起见,我个人会一次做一个)。
  • @user737159 这就是为什么通常最好将您的服务器保持在 UTC 时区(如果没有 UTC,则设置为冰岛雷克雅未克)的原因之一。保持您的业务逻辑和数据存储在 UTC 中。调整为非 UTC 时区,仅用于用户期望的演示。
【解决方案2】:

tl;博士

使用 UTC

UTC 视为“真正的时间”。特定时区的任何日期时间都是 UTC 的派生。在进行编程或系统管理工作时,请忘记您自己的本地时区。我强烈建议在您的物理桌面和数字桌面上都添加一个时钟以显示 UTC。在紧要关头,使用Time.is 等网站。

您的大部分业务逻辑、日志记录、数据存储、数据交换和数据库持久性都应该使用 UTC。调整为仅用于演示的时区。

避免使用旧的日期时间类

避免与最早版本的 Java 捆绑在一起的麻烦的旧的旧日期时间类。现在被 java.time 类所取代。

Instant

Instant 类代表UTC 中时间轴上的一个时刻,分辨率为nanoseconds

Instant now = Instant.now(); // Current moment in UTC.

指定时区

Java 虚拟机有一个当前的默认时区。这可以在从主机操作系统启动时获取。或者它可以在启动时通过配置设置进行设置。或者它可能随时被 JVM 中任何应用程序的任何线程中的任何代码更改——在执行期间影响所有其他代码!

鉴于 JVM 当前的默认时区不同,并且超出了程序员的控制范围,因此永远不要依赖它。 始终指定您希望/预期的时区

通常最好将服务器主机操作系统设置为 UTC 时区,但同样,在您的编程中永远不要依赖它。

ZonedDateTime

要将Instant 调整为时区,请生成ZonedDateTime 对象。

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );

调用toString 以生成标准ISO 8601 格式的字符串。对于其他格式,请在 Stack Overflow 中搜索 DateTimeFormatter 类。

更新您的 tz 时区数据库

时区定义及其异常情况(例如Daylight Saving Time (DST))经常变化,出奇地频繁。

Oracle 定期发布 Java 更新,其中包括 tz database 的新副本。如果您无法安装这些 Java 更新,或者如果一些粗心的政客在最后一刻对区域进行了更改,您可以使用 Oracle 的 Timezone Updater Tool 手动更新您的 Java。

Locale

知道Locale 与时区无关Locale 定义 (a) 用于翻译的人类语言,以及 (b) 决定诸如缩写、标点符号和部分顺序等问题的文化规范。所以在生成字符串时只需要一个Locale,当使用DateTimeFormatter类时。

Locale l = Locale.CANADA_FRENCH;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( l );
String output = zdt.format( f );

所以时区定义了日期时间值的含义,而Locale 定义了它的表示

关于java.time

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

Joda-Time 项目现在位于maintenance mode,建议迁移到 java.time。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。

大部分 java.time 功能在ThreeTen-Backport 中向后移植到Java 6 和7,并进一步适应ThreeTenABP 中的Android(参见How to use…)。

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuarter 等等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-04
    相关资源
    最近更新 更多