Java 2015年6月30日闰秒期间在Amazon linux AMI上运行的日历操作

Java 2015年6月30日闰秒期间在Amazon linux AMI上运行的日历操作,java,amazon-web-services,calendar,leap-second,Java,Amazon Web Services,Calendar,Leap Second,环境:AmazonLinuxAMI上的Java7(已修补)。请注意,此环境中使用NTP 我们代码的一部分定期执行预定任务。一般来说,执行的确切时间并不特别重要。但是,我们有类似的逻辑,用于计算报告间隔。报告期预计将精确到小时界限 示例代码: protected Calendar increment(ScheduledPeriodEnum scheduledPeriod, Calendar date) { Calendar next = CalendarUtils.getCalendar(

环境:AmazonLinuxAMI上的Java7(已修补)。请注意,此环境中使用NTP

我们代码的一部分定期执行预定任务。一般来说,执行的确切时间并不特别重要。但是,我们有类似的逻辑,用于计算报告间隔。报告期预计将精确到小时界限

示例代码:

protected Calendar increment(ScheduledPeriodEnum scheduledPeriod, Calendar date) {
    Calendar next = CalendarUtils.getCalendar();
    next.setTimeInMillis(date.getTimeInMillis());
    switch (scheduledPeriod) {
    case ONE_DAY:
        next.add(Calendar.DAY_OF_MONTH, 1);
        break;
    case ONE_HOUR:
        next.add(Calendar.HOUR_OF_DAY, 1);
        break;
    case FIFTEEN_MINUTE:
        next.add(Calendar.MINUTE, 15);
        break;
    case ONE_MONTH:
        next.add(Calendar.MONTH, 1);
        break;
    default:
        throw new RuntimeException("Unhandled case: " + scheduledPeriod);
    }
    return next;
}
我们将时间持久化为unix时间戳(long)值。
日历
实例都位于UTC时区

我们的理解是,Java7的日历实现没有考虑闰秒。我们还相信NTP将更新操作系统时钟

我们知道亚马逊2012年的闰秒崩溃。我们正在与他们直接沟通,以了解他们的作战准备情况

具体问题:

  • 如果我们是
    increment
    一个在闰秒前一小时边界上的日历,它会在闰秒后一小时边界上吗?还是在一小时前一秒钟

  • 我们应该如何测试/验证此代码将如何跨闰秒边界运行?黑客文件是一个好方法吗

  • 是否有一种更合适的模式/实现可以避开闰秒问题


  • 我不会太担心2015年的下一个闰秒,并且假设Linux团队在此期间已经做了很多工作来解决闰秒处理代码的任何问题,另请参见本次有趣的采访。如果linux软件再次出错,那么除了重新启动Java程序(这里Java只是后端)之外,您不能做更多的事情

    现在让我们考虑一下可能会发生什么。关于完全不知道任何闰秒的代码,如
    java.util.Date
    java.util.Calendar
    ,请记住,这些代码只看到操作系统时钟提供的内容。大多数操作系统只提供UNIX时间戳。如果它们与NTP同步,那么还要记住,NTP时间戳不计算NTP协议中指定的闰秒。他们只是重复相同的时间戳。Windows可能会在以后的任何时候触发时钟跳转,而Linux内核则会尝试更精确地应用一些闰秒处理代码并立即操纵系统时钟。无论如何,这两个操作系统都只提供类似POSIX的时间戳。Java只是看到。。。没什么

    这也回答了您的第一个具体问题:A
    gregoriacalendar
    -对象在添加一小时后将保留在小时边界上。

    关于第二个问题:

    这里讨论的只是一秒钟。但可能更麻烦的是,本地时钟甚至可能在几分钟内出错(然后在与NTP时钟同步后突然跳转)。后一种行为随时都可能发生,而不仅仅是在2015-06-30年底。所以我认为你真正的问题是时钟的单调性。这通常表明,任何测试都应该使用类似可注入时钟机制的东西。例如,您可以编写一个
    TimeSource
    -接口,该接口通过方法
    public long currentTime()
    生成任何unix时间戳(甚至可以通过计时器创建模拟跳转),然后在JUnit测试类中使用该接口提供(假)时间并观察代码的行为

    大多数人只会使用一个不知道任何闰秒的库,因为POSIX很容易理解和计算(尽管对于这些特殊的秒是不正确的)。如果没有leap second处理代码,那么这些标准库中就很难直接产生问题。否则,如果您不想对用户隐藏闰秒,那么您也可以在本文中参考我的答案

    无论您的决定是什么,闰秒对于选择合适的库/实现来说确实不够重要(线程安全、国际化等其他主题更为重要)。关于这些标准,旧的
    日历
    -内容非常糟糕。