无法识别Java 1.7的夏令时更改 [英] Java 1.7 change in daylight savings is not recognized

查看:105
本文介绍了无法识别Java 1.7的夏令时更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Java:1.7版更新71 DB:MySQL版本5.6.x

Java: ver 1.7 update 71 DB: MySQL ver 5.6.x

我们有多个正在运行的应用程序正在访问同一数据库.有两个应用程序正在Tomcat 7(版本7.0.52)上运行,两个应用程序正在使用Netty 3.10.这些服务器位于美国东部标准时间(EST)时区.

We are having multiple applications running accessing same DB. Two applications are running on Tomcat 7 (ver 7.0.52) and two applications are using Netty 3.10. The servers are on EST (US) time zone.

Web应用程序技术堆栈: 春季3.1.x Struts MVC 2.3.14 休眠3.3.x

Web Application Tech Stack: Spring 3.1.x Struts MVC 2.3.14 Hibernate 3.3.x

网络应用技术栈: 净值3.10 休眠3.3.x

Netty Application Tech Stack: Netty 3.10 Hibernate 3.3.x

我们在应用程序中使用了许多Apache log4j,通用库.

We are using many of the Apache log4j, commons libraries across the apps.

在最近的夏令时更改期间,在tomcat下运行的应用能够在DST之后获得正确的时间. Linux和DB显示正确的时间,与DST的每个时区相同.但是,在Netty上运行的服务器继续落后一小时.不仅是为应用插入的行设置的日期,所有日期值(包括日志文件中的时间戳)都显示了错误的时间.

During recent change in daylight savings time, the apps running under tomcat were able to get the right time after DST. The Linux and DB were showing correct time, as per timezone with DST. However, the ones running on Netty continued to run one hour behind. Not just the dates set for the rows inserted by the apps, all date values including time stamp in log files were showing incorrect time.

重新启动后,他们开始显示正确的时间.

Once restarted, they started showing the right time.

底层操作系统的Java使用时区详细信息.在启动过程中,未提供与时区相关的特定设置.

The Java using time zone details of the underlying OS. No specific settings related to timezone have been given as part of startup.

我认为这个问题在JDK 1.5/1.6期间已解决,并在1.7中自动处理.

I thought this problem was resolved during JDK 1.5/1.6 and is automatically handled in 1.7.

是否有一些需要应用于Java 1.7的补丁?在应用程序中是否需要明确地进行任何操作以识别DST中的更改? Tomcat如何处理这个问题?

Is there some patch that needs to be applied to Java 1.7? Is there anything explicitly needs to be done in the application to recognize change in DST? How is Tomcat taking care of this?

推荐答案

tzdata

几乎总是由 tz数据库 ,以前称为 Olson数据库,现在由IANA处理.该数据库具有全球每个地区(时区)的人们使用的按UTC偏移的过去,现在和将来的历史记录.

tzdata

Time zone data is nearly always defined by the tz database, formerly known as the Olson Database, now handled by IANA. This database has a history of past, present, and future changes in offset-by-UTC used by the people of each region (time zone) around the globe.

该数据库经常更改,因为世界各地的政客被莫名其妙地吸引来进行频繁更改.更改通常是在很少预警的情况下进行的,甚至要提前几周.

This databases changes frequently, as politicians around the world are inexplicably drawn to making frequent changes. The changes are often made with little forewarning, as little as several weeks ahead.

当不安定的政客进行更改时,如果您关心受影响的区域,则需要更新操作系统(对于本机应用程序)和Java实施(对于Java应用程序)的"tzdata". Oracle提供了 时区更新程序工具 将新的tzdata安装到其实现中. Oracle的更新版本通常包括最新的tzdata,但并非总是如此,因此,您应该阅读发行说明以获取此类详细信息.随着新计划的Oracle和APM季度发布计划的进行,使用OpenJDK实施,如果您选择与Java版本保持最新,则可能会减少手动安装tzdata的需要.

When the restless politicians make their changes, if you care about the affected zones, you need to update the "tzdata" of both your operating system (for native apps) and your Java implementation (for Java apps). Oracle provides the Timezone Updater Tool to install a fresh tzdata to their implementation. Updated versions from Oracle usually include the latest tzdata, but not always, so you should read the release notes for such details. With the new planned quarterly release cadence for Oracle & OpenJDK implementations, the need for manual installs of tzdata may decrease if you choose stay up-to-date with the Java releases.

因此,当您关心的时区的定义发生更改时,您可能需要至少在三个地方更改tzdata:

So when a time zone that you care about has its definition changed, you’ll likely need to change the tzdata in at least three places:

  • 您的计算机操作系统.
  • 您的JVM.
  • 您的数据库服务器,如果该数据库具有复杂的日期时间处理,例如 Postgres (参见示例历史记录).
  • Your computer operating system.
  • Your JVM.
  • Your database server, if that database has sophisticated date-time handling such as Postgres (see example history).

底层操作系统的Java使用时区详细信息.

The Java using time zone details of the underlying OS.

不.时区详细信息的来源来自每个Java实现的实现细节.

No. The source of time zone details comes is an implementation-detail for each Java implementation.

在我所知道的JVM实现中,JVM通过在JVM启动过程中询问主机OS来确定当前的默认时区.作为启动的一部分,可能已将默认时区作为启动参数传递给了JVM.第三,在运行时 的任何时间,任何应用程序的任何线程中的任何代码都可能更改默认时区(这绝不是好主意).

In the JVM implementations I know of, the JVM determines the current default time zone by asking the host OS as part of the JVM launching. As a part of launching, a default time zone may have been passed as a startup parameter to the JVM. Thirdly, any code in in any thread of any app at any moment during runtime may change the default time zone (this is almost never a good idea).

但是在所有这些情况下,区域的定义都存储在JVM本身内.因此,如果感兴趣的任何区域已更改,则需要保持JVM的tzdata为最新.

But in all these cases, the definition of the zones is stored within the JVM itself. So you need to keep the JVM’s tzdata up-to-date if any zones of interest have have changed.

在Netty上运行的人继续落后一小时……

ones running on Netty continued to run one hour behind …

重新启动后,他们开始显示正确的时间.

Once restarted, they started showing the right time.

没有看到您应用的程序,也没有看到Netty的程序,我们只能猜测特定的问题.我怀疑该应用程序可能无法正确处理日期时间.

Without seeing the programming for your apps, and without seeing the programming of Netty, we can only guess as to the specific problem. I suspect the app may be failing to handle date-times properly.

捕捉时刻的正确方法是在 UTC 中进行.在Java中,这意味着Instant类. Instant 类代表一个时刻在 UTC 中的时间轴上,分辨率为纳秒(最多十进制的九(9)位数字).

The proper way to capture a moment is to do so in UTC. In Java, that means the Instant class. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).

Instant instant = Instant.now() ;  // Capture current moment in UTC.

或者,您可以捕获特定时区的时刻.

Alternatively, you could capture the moment for a particular time zone.

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

您的应用在启动时可能仅使用了与UTC偏移的缓存.

Your app may be using a mere offset-from-UTC cached when the app launched.

ZoneOffset offset = ZoneOffset.systemDefault() ; // Do NOT cache this, as it will be invalid after a DST cut-over.

时区总是比仅 offset-from-UTC 更可取.偏移量仅是数小时,数分钟和数秒的时间,无非是一无所有.相比之下,时区是过去,现在和将来使用的偏移量的历史记录由特定地区的人.

A time zone is always preferable to a mere offset-from-UTC. An offset is simply a number of hours, minutes, and seconds – nothing less, nothing more. In contrast, a time zone is a history of past, present, and future changes in offset used by the people of a particular region.

如果应用在启动时检测到当前正在使用的偏移量,并无限期地缓存了该偏移量,则在夏令时(DST)转换.

If an app detected the offset currently in use when launched, and cached that offset indefinitely, its use would no longer be correct after a Daylight Saving Time (DST) cut-over.

例如,当前在America/Los_Angeles区域中,自UTC的偏移量比UTC -08:00晚8个小时.但是在几天中,即三月的第二个星期日,DST废话生效,每个人都将时钟提前一个小时,从而将使用中的UTC偏移量更改为比UTC落后七个小时,即-07:00.如果-08:00缓存不当,则捕获当前时刻的尝试将是错误的.

For example, currently in America/Los_Angeles zone, the offset-from-UTC is eight hours behind UTC, -08:00. But in several days, on the second Sunday in March, the DST nonsense takes effect, when everyone sets their clocks ahead an hour, thereby changing the offset-from-UTC in use to seven hours behind UTC, -07:00. If that -08:00 had been inappropriately cached, the attempts at capturing the current moment will be incorrect.

OffsetDateTime odt = OffsetDateTime.now( inappropriatelyCachedOffset ) ;  // Capturing the wrong wall-clock time. 

同样,预防很简单……使用时区,而不是与UTC偏移.

Again, the prophylactic is simple… Use time zone, not offset-from-UTC.

continent/region的格式指定正确的时区名称,例如, America/Montreal Africa/Casablanca Pacific/Auckland.切勿使用3-4个字母的缩写,例如ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!).

Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

造成您明显行为的另一个可能原因是您的应用程序从数据库服务器获取了当前分区的日期时间,该数据库服务器上自己的tzdata已过时,但尚未更新以反映该区域的定义中的更改.

Another possible cause of your apparent behavior might be your app getting the current zoned date-time from a database server where the database’s own tzdata is now outdated, not yet updated to reflect changes in that zone’s definition.

如上所述,某些复杂的数据库(例如Postgres)具有自己的内部存储的tzdata信息.预防措施是使数据库服务器保持其版本更新为最新,或者手动安装更新的tzdata.

As discussed up above, some sophisticated databases such as Postgres have their own internally-stored tzdata information. The prophylactic is to either keep the database server up-to-date with its version updates, or manually install an updated tzdata.

这也是在UTC中思考,工作,记录,存储和交换日期时间值的另一个原因.在整个问题讨论中,时钟可能已正确设置为当前时间.这是对当时可能出问题的区域的解释.如果电流是在UTC中捕获的,则不会在时区进行任何调整,因此不会有问题.

This is also yet another reason to think, work, log, store, and exchange date-time values in UTC. Throughout this discussion of problems, the clock may have been set correctly to the current time. It is the interpretation of that time through a zone where things may have gone wrong. If the current had been captured in UTC, there would be no adjustment into a time zone, and therefore no problem.

因此,学习在UTC中思考.在以程序员或管理员身份工作时,请忘记自己的时区.将您桌上的第二个时钟设置为UTC.在UTC中进行所有日志记录和记笔记.将UTC视为唯一的真实时间,所有其他分区时间仅是变化而已.

So learn to think in UTC. While on the job as a programmer or administrator, forget about your own parochial time zone. Keep a second clock on your desk set to UTC. Do all your logging and note-taking in UTC. Think of UTC as the One True Time, with all other zoned times being but mere variations.

同样,Instant.now()是您的朋友.

当您需要序列化日期时间值时,请使用标准的 ISO 8601 格式.该标准经过精心设计,具有实用性和合理性.这些格式很容易通过机器解析,也很容易被跨文化的人类阅读.

When you need to serialize a date-time value, use the standard ISO 8601 formats only. This standard was cleverly designed to be practical and sensible. The formats are easy to parse by machine yet also easy to read by humans across cultures.

在UTC中,格式为YYYY-MM-DDTHH:MM:SS.SZ.中间的T将年-月-日与小时-分钟-秒分开.末尾的ZZulu的缩写,表示UTC.

For a moment in UTC, the format is YYYY-MM-DDTHH:MM:SS.SZ. The T in the middle separates year-month-day from hour-minute-second. The Z on the end is short for Zulu and means UTC.

2018-01-23T12:34:56.123456789Z

2018-01-23T12:34:56.123456789Z

java.time 类在解析/生成字符串时默认使用ISO 8601格式.

The java.time classes use ISO 8601 formats by default when parsing/generating strings.

String output = instant.toString() ;

…和…

Instant instant = Instant.parse( "2018-01-23T12:34:56.123456789Z" ) ;

使用 java.time

另一个要点:切勿使用与Java最早版本捆绑在一起的麻烦的旧日期时间类.他们是一个可怕的烂摊子,要避免.它们现在已成为旧版,完全被 java.time 类所取代.上面看到的所有代码都使用现代的 java.time 类.

Use java.time classes

Another important point: Never use the troublesome old date-time classes bundled with the earliest versions of Java. They are a terrible wretched mess, to be avoided. They are now legacy, supplanted entirely by the java.time classes. All the code seen above usese the modern java.time classes.

是否有一些补丁需要应用于Java 1.7?

Is there some patch that needs to be applied to Java 1.7?

不是我所知道的.但是您可能需要如上所述在JVM和数据库服务器中更新tzdata.

Not that I am aware of. But you may need to update your tzdata as discussed above, both in your JVM and in your database server.

应用程序中是否需要明确进行任何操作以识别DST中的更改?

Is there anything explicitly needs to be done in the application to recognize change in DST?

不.在DST转换 IF 期间无需执行任何操作,您的tzdata是最新的(a)在JVM中和(b)在数据库中,并且您使用时区而不是只是补偿.

No. You need not do anything during a DST cut-over IF your tzdata is up-to-date (a) in your JVM and (b) in your database, AND you use time zones rather than mere offsets.

Tomcat如何处理这个问题?

How is Tomcat taking care of this?

不. Apache Tomcat与您的日期时间问题无关. Tomcat对时区和偏移量一无所知.那是您的JVM的业务,而不是Tomcat的业务.

No. Apache Tomcat has nothing to do with your date-time issues. Tomcat knows nothing about time zones and offsets. That is the business of your JVM, not Tomcat.

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

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

Joda-Time 项目,现在位于<一个href ="https://en.wikipedia.org/wiki/Maintenance_mode" rel ="nofollow noreferrer">维护模式,建议迁移到要了解更多信息,请参见 Oracle教程 .并在Stack Overflow中搜索许多示例和说明.规范为 JSR 310 .

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

您可以直接与数据库交换 java.time 对象.使用符合 JDBC驱动程序 /jeps/170"rel =" nofollow noreferrer> JDBC 4.2 或更高版本.不需要字符串,不需要java.sql.*类.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

在哪里获取java.time类?

Where to obtain the java.time classes?

  • Java SE 8 Java SE 9 和更高版本
    • 内置.
    • 具有捆绑的实现的标准Java API的一部分.
    • Java 9添加了一些次要功能和修复.
    • Java SE 8, Java SE 9, and later
      • Built-in.
      • Part of the standard Java API with a bundled implementation.
      • Java 9 adds some minor features and fixes.
      • Later versions of Android bundle implementations of the java.time classes.
      • For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….

      > ThreeTen-Extra 项目扩展了java.time与其他班级.该项目是将来可能向java.time添加内容的试验场.您可能会在这里找到一些有用的类,例如 Interval YearWeek YearQuarter 更多.

      这篇关于无法识别Java 1.7的夏令时更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆