简体   繁体   English

(Oracle)Java JVM如何知道闰秒发生了什么?

[英]How does the (Oracle) Java JVM know a leap second is occurring?

A leap second will occur on June 30, 2015. Different Operating Systems seem to handle this situation differently. 闰秒将在2015年6月30日发生 。不同的操作系统似乎以不同的方式处理这种情况。 In my particular case, we are running a Red Hat 6.4 system with custom Java (JDK 1.7) software that is heavily time-dependent. 在我的特定情况下,我们运行的Red Hat 6.4系统具有严重依赖于时间的自定义Java(JDK 1.7)软件。 According to some recent Red Hat released information I found, our system's NTP daemon will ensure the OS automatically handle the leap second by repeating 23:59:59 twice. 根据最近我发现的一些Red Hat发布的信息 ,我们系统的NTP守护进程将确保操作系统通过重复23:59:59两次自动处理闰秒。

My question is: if I have a long running JDK 1.7 process, how does it know that a leap second is occurring? 我的问题是:如果我有一个长期运行的JDK 1.7进程,它是如何知道闰秒发生的? What I mean is, how does Java ultimately know the IERS people have decided to insert a leap second? 我的意思是,Java最终如何知道IERS人们决定插入闰秒? The Date documentation seems to indicate is aware of leap seconds, but seems unhelpfully vague. 日期文档似乎表明已经知道闰秒,但似乎没有任何帮助。 Can I assume the JDK, when the appropriate Date object is constructed or Calendar.getInstance() is invoked, it is a pass through to the underlying OS's date-time handling to get the appropriate "real" time value? 我可以假设JDK,当构造适当的Date对象或调用Calendar.getInstance() ,它是否传递给底层操作系统的日期时间处理以获得适当的“实际”时间值? (Which, in my case, sounds like it would repeat second 23:59:59, because that's how the OS will handle it). (在我的情况下,听起来它会重复第二次23:59:59,因为这就是操作系统将如何处理它)。

The Answer by assylias is correct. assylias 的回答是正确的。 This Answer adds some thoughts triggered by a comment on that Answer. 本答案增加了一些由该答案评论引发的想法。 The comment referred to calculating elapsed time over the midnight when a Leap Second is scheduled. 该评论涉及计算在安排闰秒的午夜时间的经过时间。

This Answer does address the original Question as well by pointing out that for practical usage, the issue of Leap Second is moot, ignored by the date-time frameworks. 本答案也解决了原始问题,指出在实际应用中,闰秒问题没有实际意义,被日期时间框架所忽略。

Leap Seconds Ignored 闰秒被忽略了

All the common Java date-time frameworks ignore leap seconds, as I understand it. 正如我所理解的那样,所有常见的Java日期时间框架都忽略了闰秒。 These include: 这些包括:

  • java.time java.time
  • Joda-Time 乔达时间
  • java.util.Date/.Calendar (now outmoded by java.time & Joda-Time) java.util.Date/.Calendar(现在已经过时了java.time和Joda-Time)

Doc 文件

Here are excerpts from each frameworks documentation showing they effectively ignore Leap Seconds. 以下是每个框架文档的摘录,显示它们实际上忽略了Leap Seconds。 The emphasis in bold is mine. 大胆的重点是我的。

The java.time doc for Instant class: Instant类的java.time文档:

… Given the complexity of accurate timekeeping described above, this Java API defines its own time-scale, the Java Time-Scale. ...鉴于上述精确计时的复杂性,此Java API定义了自己的时间尺度Java Time-Scale。

The Java Time-Scale divides each calendar day into exactly 86400 subdivisions, known as seconds. Java Time-Scale将每个日历日划分为86400个细分,称为秒。 These seconds may differ from the SI second. 这些秒可能与SI秒不同。 It closely matches the de facto international civil time scale, the definition of which changes from time to time. 它与事实上的国际民事时间表紧密匹配,其定义随时变化。

The Java Time-Scale has slightly different definitions for different segments of the time-line, each based on the consensus international time scale that is used as the basis for civil time. Java时间尺度对时间线的不同部分的定义略有不同,每个部分都基于用作民用时间基础的共识国际时间尺度。 Whenever the internationally-agreed time scale is modified or replaced, a new segment of the Java Time-Scale must be defined for it. 每当修改或替换国际商定的时间尺度时,必须为其定义Java时间尺度的新部分。 Each segment must meet these requirements: 每个细分必须满足以下要求:

  • the Java Time-Scale shall closely match the underlying international civil time scale; Java时标应与基础国际民用时标紧密匹配;
  • the Java Time-Scale shall exactly match the international civil time scale at noon each day; Java时标应与每天中午的国际民用时标完全匹配;
  • the Java Time-Scale shall have a precisely-defined relationship to the international civil time scale. Java时标应与国际民用时标具有精确定义的关系。

There are currently, as of 2013, two segments in the Java time-scale. 目前,截至2013年,Java时间范围内有两个部分。

For the segment from 1972-11-03 (exact boundary discussed below) until further notice, the consensus international time scale is UTC (with leap seconds). 对于从1972-11-03(下面讨论的确切边界)直到另行通知的段,共识国际时间尺度是UTC(具有闰秒)。 In this segment, the Java Time-Scale is identical to UTC-SLS. 在此段中,Java Time-Scale与UTC-SLS相同。 This is identical to UTC on days that do not have a leap second. 这与没有闰秒的天数相同。 On days that do have a leap second, the leap second is spread equally over the last 1000 seconds of the day, maintaining the appearance of exactly 86400 seconds per day . 在具有闰秒的日子里,闰秒在一天的最后1000秒内平均分布,每天保持恰好86400秒的外观

For the segment prior to 1972-11-03, extending back arbitrarily far, the consensus international time scale is defined to be UT1, applied proleptically, which is equivalent to the (mean) solar time on the prime meridian (Greenwich). 对于1972-11-03之前的段,任意向后延伸,共识的国际时间尺度被定义为UT1,在概率上应用,这相当于本初子午线(格林威治)的(平均)太阳时。 In this segment, the Java Time-Scale is identical to the consensus international time scale. 在此细分中,Java时间尺度与共识国际时间尺度相同。 The exact boundary between the two segments is the instant where UT1 = UTC between 1972-11-03T00:00 and 1972-11-04T12:00. 两个段之间的确切边界是UT1 = UTC在1972-11-03T00:00和1972-11-04T12:00之间的瞬间。

Implementations of the Java time-scale using the JSR-310 API are not required to provide any clock that is sub-second accurate, or that progresses monotonically or smoothly. 使用JSR-310 API实现Java时标不需要提供亚秒精确或单调或平滑进展的任何时钟。 Implementations are therefore not required to actually perform the UTC-SLS slew or to otherwise be aware of leap seconds. 因此,实现不需要实际执行UTC-SLS转换或以其他方式了解闰秒。 JSR-310 does, however, require that implementations must document the approach they use when defining a clock representing the current instant. 但是,JSR-310要求实现必须记录它们在定义表示当前时刻的时钟时使用的方法。 See Clock for details on the available clocks. 有关可用时钟的详细信息,请参见时钟。

The Java time-scale is used for all date-time classes. Java时标用于所有日期时间类。 This includes Instant, LocalDate, LocalTime, OffsetDateTime, ZonedDateTime and Duration. 这包括Instant,LocalDate,LocalTime,OffsetDateTime,ZonedDateTime和Duration。

Joda-Time FAQ : Joda-Time常见问题

Joda-Time does not support leap seconds . Joda-Time 不支持闰秒 Leap seconds can be supported by writing a new, specialized chronology, or by making a few enhancements to the existing ZonedChronology class. 通过编写新的专业年表或对现有的ZonedChronology类进行一些增强,可以支持闰秒。 In either case, future versions of Joda-Time will not enable leap seconds by default. 在任何一种情况下,Joda-Time的未来版本默认情况下都不会启用闰秒。 Most applications have no need for it, and it might have additional performance costs. 大多数应用程序不需要它,并且可能会有额外的性能成本。

The java.util.Date class doc : java.util.Date类doc

A second is represented by an integer from 0 to 61; 第二个由0到61的整数表示; the values 60 and 61 occur only for leap seconds and even then only in Java implementations that actually track leap seconds correctly . 值60和61仅在闰秒发生,甚至仅在实际正确跟踪闰秒的Java实现中发生

As far as I know, the OpenJDK and Oracle-provided implementations do not track leap seconds. 据我所知,OpenJDK和Oracle提供的实现跟踪闰秒。 Please post such documentation if you find it. 如果找到,请发布此类文档。

No Leap Second When Calculating Elapsed Time 计算经过时间时没有闰秒

Accordingly, these frameworks will not report the extra leap second when calculating elapsed time. 因此,这些框架在计算经过时间时不会报告额外的闰秒。

Here is some example code calculating elapsed time from minute before midnight to minute after, on June 30 to July 1, 2015 when a Leap Second is scheduled. 以下是一些示例代码,用于计算2015年6月30日至7月1日安排闰秒时从午夜到分钟之间的经过时间。 This code tests Joda-Time 2.8.1 and java-time in java version "1.8.0_45" . 此代码在java version "1.8.0_45"测试Joda-Time 2.8.1和java-time。 I ignored java.util.Date/.Calendar as I avoid those classes whenever possible; 我忽略了java.util.Date/.Calendar,因为我尽可能避免使用这些类; feel free to add code here for that case if desired. 如果需要,可以随意在此处添加代码。

First Joda-Time . 第一次Joda-Time

// Joda-Time 2.8.1
DateTime startJoda = new DateTime( 2015, 06, 30, 23, 59, 00, DateTimeZone.UTC );
DateTime stopJoda = new DateTime( 2015, 07, 01, 00, 01, 00, DateTimeZone.UTC );
long elapsedMillisJoda = ( stopJoda.getMillis( ) - startJoda.getMillis( ) );

System.out.println( "startJoda: " + startJoda + " stopJoda: " + stopJoda + " = elapsedMillisJoda: " + elapsedMillisJoda );

… and java.time ...和java.time ...

// java.time
ZonedDateTime startZdt = ZonedDateTime.of( 2015, 06, 30, 23, 59, 00, 00, ZoneOffset.UTC );
ZonedDateTime stopZdt = ZonedDateTime.of( 2015, 07, 01, 00, 01, 00, 00, ZoneOffset.UTC );
long elapsedMillisZdt = startZdt.until( stopZdt, ChronoUnit.MILLIS );

System.out.println( "startZdt: " + startZdt + " stopZdt: " + stopZdt + " = elapsedMillisZdt: " + elapsedMillisZdt );

When run, we see a result of even numbers, exactly two minutes, 120 seconds, or 120,000 milliseconds. 运行时,我们会看到偶数的结果,恰好是两分钟,120秒或120,000毫秒。

startJoda: 2015-06-30T23:59:00.000Z stopJoda: 2015-07-01T00:01:00.000Z = elapsedMillisJoda: 120000
startZdt: 2015-06-30T23:59Z stopZdt: 2015-07-01T00:01Z = elapsedMillisZdt: 120000

About java.time 关于java.time

The java.time framework is built into Java 8 and later. java.time框架内置于Java 8及更高版本中。 These classes supplant the troublesome old legacy date-time classes such as java.util.Date , Calendar , & SimpleDateFormat . 这些类取代了麻烦的旧遗留日期时间类,如java.util.DateCalendarSimpleDateFormat

The Joda-Time project, now in maintenance mode , advises migration to the java.time classes. 现在处于维护模式Joda-Time项目建议迁移到java.time类。

To learn more, see the Oracle Tutorial . 要了解更多信息,请参阅Oracle教程 And search Stack Overflow for many examples and explanations. 并搜索Stack Overflow以获取许多示例和解释。 Specification is JSR 310 . 规范是JSR 310

Using a JDBC driver compliant with JDBC 4.2 or later, you may exchange java.time objects directly with your database. 使用符合JDBC 4.2或更高版本的JDBC驱动程序 ,您可以直接与数据库交换java.time对象。 No need for strings nor java.sql.* classes. 不需要字符串也不需要java.sql。*类。

Where to obtain the java.time classes? 从哪里获取java.time类?

The ThreeTen-Extra project extends java.time with additional classes. ThreeTen-Extra项目使用其他类扩展了java.time。 This project is a proving ground for possible future additions to java.time. 该项目是未来可能添加到java.time的试验场。 You may find some useful classes here such as Interval , YearWeek , YearQuarter , and more . 您可以在这里找到一些有用的类,比如IntervalYearWeekYearQuarter ,和更多

It depends on your jdk version. 这取决于你的jdk版本。 If for example you are running update 80, you can check the release notes : 例如,如果您正在运行更新80,则可以查看发行说明

JDK 7u80 contains IANA time zone data version 2015a. JDK 7u80包含IANA时区数据版本2015a。 For more information, refer to Timezone Data Versions in the JRE Software. 有关更多信息,请参阅JRE软件中的时区数据版本。

Then follow the link to the timezone data versions and find 2015a. 然后点击时区数据版本的链接,找到2015a。 Then follow the link to TZ Updater version1.4.11 : 然后点击TZ Updater version1.4.11的链接

New leap second 2015-06-30 23:59:60 UTC as per IERS Bulletin C 49. (Thanks to Tim Parenti.) 新的闰秒2015-06-30 23:59:60 UTC根据IERS Bulletin C 49.(感谢Tim Parenti。)

It does not seem to have been included before so if you are running an older version of JDK 7 you will probably not get the adjustment. 它似乎之前没有被包括在内,所以如果您运行的是旧版本的JDK 7,您可能无法进行调整。 More information about how it works internally is available here . 有关内部工作原理的更多信息,请点击此处

To be honest I have never tested to see how it works in practice. 说实话,我从未测试过它在实践中是如何运作的。

These are my actual obervations, running a real-time system on RHEL 6.3, with Oracle Java JDK 1.7.0_55-b13 (Ie: an out-of-date JDK). 这些是我在RHEL 6.3上运行实时系统的实际操作,使用Oracle Java JDK 1.7.0_55-b13(即:过时的JDK)。 I added debugging code that kicked on, logging a new DateTime() every 0.5 seconds a minute prior to the leap second at June 30, 2015 23:59 UTC, and then kicked off after the leap second was over. 我添加了启动的调试代码,在2015年6月30日23:59 UTC的闰秒之前每0.5秒记录一次新的DateTime(),然后在闰秒结束后启动。 Log follows (for the curious, the double number printed is the number of seconds since the J2000 epoch ) 记录如下(好奇的是,打印的双号是自J2000纪元以来的秒数)

2015-06-30 23:59:59.316 18349217 [main] INFO  - Leaper's time is 488980799.316000 (Tue Jun 30 23:59:59 GMT-00:00 2015)
2015-06-30 23:59:59.817 18349718 [main] INFO  - Leaper's time is 488980799.816000 (Tue Jun 30 23:59:59 GMT-00:00 2015)
2015-07-01 00:00:00.317 18350218 [main] INFO  - Leaper's time is 488980800.317000 (Wed Jul 01 00:00:00 GMT-00:00 2015)
2015-07-01 00:00:00.817 18350718 [main] INFO  - Leaper's time is 488980800.817000 (Wed Jul 01 00:00:00 GMT-00:00 2015)
2015-07-01 00:00:01.318 18351219 [main] INFO  - Leaper's time is 488980801.318000 (Wed Jul 01 00:00:01 GMT-00:00 2015)

Unfortunately, that doesn't tell me much, except that it did not insert the canonical leap second at 23:59:60 (as both assylias's and Basil Bourque's answers indicate would happen). 不幸的是,这并没有告诉我多少,除了它没有在23:59:60插入规范的闰秒(因为assylias和Basil Bourque的答案都表明会发生)。 My hope was that 'new Date()' would reach down to the underlying OS (RHEL 6.3, which supposedly accounts for the leap seconds properly) to ask the current time. 我希望'新的Date()'可以达到底层操作系统(RHEL 6.3,据称可以正确计算闰秒)来询问当前时间。 That did not seem to be the case. 情况似乎并非如此。

I did not have the resources to run any other combinations of JDK version and RHEL version to test out the effects. 我没有资源运行JDK版本和RHEL版本的任何其他组合来测试效果。 My current best guess is that the documentation Basil Bourque found about spreading the leap second over the last 1000 seconds of the day applies to JDK 1.8 and newer (as it is part of the Instant documentation, which is a Java 8 feature). 我目前最好的猜测是,Basil Bourque在当天的最后1000秒内发现闰秒的文档适用于JDK 1.8及更新版本(因为它是Instant 8文档的一部分,这是Java 8的一项功能)。 For my particular case, since my older JDK 1.7.0_55 did not have the leap second adjustment for 2015, I think assylias's observation applies. 对于我的特殊情况,由于我的旧JDK 1.7.0_55没有2015年的闰秒调整,我认为assylias的观察适用。 Namely, that our real-time processes are now running 1 second ahead, oblivious to the leap second. 也就是说,我们的实时流程现在提前1秒运行,不知道闰秒。

Lesson learned here? 在这里学到的经验? Make sure your real-time systems are fully patched with the latest updates, if you want to be sure they account for upcoming leap seconds. 如果您想确保它们考虑即将到来的闰秒,请确保您的实时系统已完全修补最新更新。 I'll have to do some observations and log analysis, but our particular system is now likely running 1 second ahead of real time, and we'll need to restart our services to fall-back in line. 我将不得不做一些观察和日志分析,但我们的特定系统现在可能比实时提前1秒运行,我们需要重新启动我们的服务以便回退。

Don't forget that the leap second occurs at 23:59:59 in UT0 this is applied at the same instant at all time zones across the world so if you are in zone time plus 8 it will occur at 23:59:59 - 8 = 15:59:59. 不要忘记闰秒发生在UT0的23:59:59,这是在世界各地的所有时区的同一时刻应用,所以如果你在区域时间加8,它将发生在23:59:59 - 8 = 15:59:59

Any local time changes due to 'daylight saving' are ignored. 由于“夏令时”而导致的任何本地时间更改都将被忽略。

The following second is 23:59:60 then 00:00:00. 以下是23:59:60然后00:00:00。

Note the specification for leap seconds allows for + - 1 or 2 seconds to be inserted at the end of December or June. 请注意,闰秒规范允许在12月或6月底插入+ - 1或2秒。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 JVM 如何知道何时抛出 NullPointerException - How does the JVM know when to throw a NullPointerException JVM如何在运行时知道对象的类 - How does JVM know class of an object at runtime 有人知道Java / JVM的嵌入式博客引擎吗? - Does anyone know of an embedded blog engine for Java/the JVM? Java时间超过linux时间(闰秒) - Java time ahead of linux time (leap second) 动态(运行时)多态如何在Java中工作? 换句话说,JVM如何知道要调用的方法? - How does Dynamic (run-time) polymorphism work in java? In other words how does the JVM know which methods to call? OpenJDK JVM是否与Oracle Java SE JVM相同? - Is the OpenJDK JVM the same as the Oracle Java SE JVM? JVM如何知道在运行时捕获异常的位置? - How does the JVM know where to catch an exception at runtime? JVM如何知道哪些行程序抛出异常? - How does the JVM know what line programs throw exceptions in? 即使刚刚发生了leap秒,如何用Java安排任务在午夜进行呢? - How can a task be scheduled in Java to occur at midnight, even if a leap second has just occurred? 考虑到新引入的闰秒,1岁(java)lib如何正确执行UTC时间格式化 - How can a 1 year old (java) lib correctly perform an UTC Time formatting, considering a newly introduced leap second
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM