亚述的答案是正确的。此答案添加了一些由对该答案的评论触发的想法。该评论提到在安排闰秒时计算午夜经过的时间。
这个答案也确实解决了最初的问题,指出对于实际使用,闰秒的问题是没有意义的,被日期时间框架所忽略。
忽略闰秒
据我所知,所有常见的Java日期时间框架都忽略了闰秒。这些包括:
- java.time
- 城大时间
- java.util.Date/.Calendar(现在被java.time和Joda-Time淘汰)
医生
以下是每个框架文档的摘录,表明它们有效地忽略了闰秒。粗体字的强调是我的。
Instant
类的 java.time 文档:
...鉴于上述精确计时的复杂性,此 Java API 定义了自己的时间尺度,即 Java 时间尺度。
Java 时间刻度将每个日历日划分为 86400 个细分,称为秒。这些秒数可能与 SI 秒数不同。它与事实上的国际民事时间尺度非常吻合,其定义不时变化。
Java时间尺度对时间线的不同部分的定义略有不同,每个定义都基于用作民事时间基础的共识国际时间尺度。每当修改或替换国际商定的时间尺度时,必须为其定义Java时间尺度的新部分。每个航段必须满足以下要求:
- Java时间尺度应与基本的国际民事时间尺度紧密匹配;
- Java时间尺度应与每天中午的国际民事时间尺度完全一致;
- Java时间尺度应与国际民事时间尺度有精确界定的关系。
截至2013年,Java时间尺度目前有两个部分。
对于1972-11-03的段(下面讨论的确切边界),直到另行通知,共识国际时间尺度是UTC(带有闰秒)。在此段中,Java 时间尺度与 UTC-SLS 相同。这与没有闰秒的日子里的UTC相同。在有闰秒的日子里,闰秒在一天的最后1000秒内平均分布,保持每天正好86400秒的外观。
对于1972-11-03之前的段,任意向后延伸,共识国际时间尺度被定义为UT1,按比例应用,相当于本初子午线上的(平均)太阳时(格林威治)。在这一部分中,Java时间尺度与共识国际时间尺度相同。两段之间的确切边界是 UT1 = UTC 在 1972-11-03T00:00 和 1972-11-04T12:00 之间的时刻。
使用 JSR-310 API 实现 Java 时间刻度不需要提供任何亚秒级精度或单调或平稳进行时钟。因此,实现不需要实际执行 UTC-SLS 压摆或以其他方式了解闰秒。但是,JSR-310 确实要求实现必须记录它们在定义表示当前时刻的时钟时使用的方法。有关可用时钟的详细信息,请参阅时钟。
Java 时间刻度用于所有日期时间类。这包括 Instant、LocalDate、LocalTime、OffsetDateTime、ZonedDateTime 和 Duration。
商大时间常见问题:
Joda-Time不支持闰秒。可以通过编写新的专用年表或对现有的 ZonedChronology 类进行一些增强来支持闰秒。在任何一种情况下,Joda-Time的未来版本默认情况下都不会启用闰秒。大多数应用程序不需要它,并且可能会有额外的性能成本。
Java.util.Date 类文档:
秒由从0到61的整数表示;值 60 和 61 仅出现在闰秒中,即使如此,也仅在实际正确跟踪闰秒的 Java 实现中出现。
据我所知,OpenJDK和Oracle提供的实现不跟踪闰秒。如果找到,请发布此类文档。
计算已用时间时无闰秒
因此,这些框架在计算经过的时间时不会报告额外的闰秒。
下面是一些示例代码,用于计算从午夜前一分钟到午夜过后的一分钟(2015 年 6 月 30 日至 7 月 1 日计划闰秒)的经过时间。此代码在 中测试 Joda-Time 2.8.1 和 java-time。我忽略了java.util.Date/。日历,因为我尽可能避免这些课程;如果需要,可以随意在此处为这种情况添加代码。java version "1.8.0_45"
第一次 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 );
...和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 );
运行时,我们看到偶数的结果,正好是两分,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
关于 java.time
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧旧日期时间类,如java.util.Date
,Calendar
和SimpleDateFormat
。
Joda-Time 项目现在处于维护模式,建议迁移到 java.time 类。
要了解更多信息,请参阅 Oracle 教程。搜索 Stack Overflow 以获取许多示例和解释。规格是JSR 310。
使用与 JDBC 4.2 或更高版本兼容的 JDBC 驱动程序,您可以直接与数据库交换 java.time 对象。不需要字符串,也不需要java.sql.*类。
从哪里获取 java.time 类?
ThreeTen-Extra 项目通过其他类扩展了 java.time。这个项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
等。