2

环境:Amazon Linux AMI 上的 Java 7(已修补)。请注意,在此环境中使用 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 时间戳(长)值。所有Calendar实例都在 UTC 时区。

我们的理解是 Java 7 的日历实现不考虑闰秒。我们也相信 NTP 会更新操作系统时钟。

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

具体问题:

  1. 如果我们increment的日历在闰秒之前的一个小时边界上,它会在闰秒之后的一个小时边界上吗?还是整点前一秒?

  2. 我们应该如何测试/验证这段代码将如何跨越闰秒边界?被黑的 NIST 跳跃文件是一个好方法吗?

  3. 是否有更合适的模式/实现可以回避闰秒问题?

4

1 回答 1

2

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

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

这也回答了您的第一个具体问题:添加GregorianCalendar小时后,-object 将保持在小时边界上。

关于你的第二个问题:

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

广告 3.) 大多数人只会使用不知道任何闰秒的库,因为 POSIX 易于理解和计算(尽管在这些特殊秒数方面不正确)。如果没有闰秒处理代码,几乎不会有直接源于此类标准库的问题。否则,如果您不愿意向用户隐藏闰秒,那么您也可以在此SO-post中查阅我的答案。

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

于 2015-01-14T19:00:32.883 回答