DST 切换日的 Joda Time getSecondOfDay

Joda Time getSecondOfDay on DST switch day

我在尝试获取 DST 切换日午夜以来的秒数时,从 Joda Time 得到了奇怪的行为。

我的代码:

public static void main(String[] args) {

    DateTimeZone timeZone = DateTimeZone.getDefault();
    System.out.println(timeZone);

    DateTimeFormatter dateFormatter = DateTimeFormat.shortDate();
    DateTimeFormatter dateTimeFormatter = DateTimeFormat.fullDateTime();
    LocalDate date = new LocalDate(2016, 10, 29);
    for (int i=0; i<3; i++) {

        System.out.println();
        System.out.println(dateFormatter.print(date) + ":");

        {
            DateTime instant = new DateTime(date.getYear(), date.getMonthOfYear(), date.getDayOfMonth(), 1, 0, 0, timeZone);
            System.out.println(dateTimeFormatter.print(instant) + " // " + instant.getSecondOfDay() + " // " + instant.getZone().getOffset(instant));
        }

        {
            DateTime instant = new DateTime(date.getYear(), date.getMonthOfYear(), date.getDayOfMonth(), 10, 0, 0, timeZone);
            System.out.println(dateTimeFormatter.print(instant) + " // " + instant.getSecondOfDay() + " // " + instant.getZone().getOffset(instant));
        }

        date = date.plusDays(1);
    }
}

输出:

Europe/Berlin

29.10.16:
Samstag, 29. Oktober 2016 01:00 Uhr MESZ // 3600 // 7200000
Samstag, 29. Oktober 2016 10:00 Uhr MESZ // 36000 // 7200000

30.10.16:
Sonntag, 30. Oktober 2016 01:00 Uhr MESZ // 3600 // 7200000
Sonntag, 30. Oktober 2016 10:00 Uhr MEZ // 36000 // 3600000

31.10.16:
Montag, 31. Oktober 2016 01:00 Uhr MEZ // 3600 // 3600000
Montag, 31. Oktober 2016 10:00 Uhr MEZ // 36000 // 3600000

(德语翻译:MEZ = CET,MESZ = CEST)

如您所见,10 月 30 日是夏令时切换日。切换发生在凌晨 2 点到 3 点之间。如果我没记错的话,夏令时是 UTC+2,冬令时是 UTC+1,所以凌晨 3 点,时钟调回凌晨 2 点。

现在这显然意味着 2-3 的重叠,但我的测试使用上午 1 点和上午 10 点,这应该是明确的。我预计 CEST 10 月 30 日凌晨 1 点的瞬间是自午夜以来的 3600 秒,而 CET 10 月 30 日上午 10 点的瞬间是自午夜(11 小时)以来的 39600 秒。但是 getSecondOfDay() returns 午夜后 10 小时。

我能想到的唯一含义(除了一个愚蠢的错误)是 getSecondOfDay() 实际上不是 return 自午夜以来的秒数,而是其他东西。然而,我在网上找到的每个例子似乎都暗示它 return 自午夜以来的秒数。据我所知,"midnight" 也没有 DST 相关的重新定义。

为什么我会得到这些结果? 在这种情况下 getSecondOfDay() 意味着什么? 我还应该怎么做才能获得自午夜以来的秒数?

字段 SECOND_OF_DAY 本质上基于本地时间轴。 这意味着,它不计算实际经过的 SI 或 POSIX 秒从午夜开始,但仅代表挂钟上显示的时钟罢工的标称计数,每个昼夜周期始终有 24 hours/strikes,忽略任何 DST 问题。或者另一种描述:试想这个字段显示秒针在钟面上的位置。

但您可以以另一种方式确定实际经过的秒数。 class DateTime 是一个瞬间,因此您可以先确定午夜的瞬间,然后再确定上午 10 点的第二个瞬间。然后你应用这个表达式:

int elapsedSecondsSinceMidnight =
  Seconds.secondsBetween(instantMidnight, instant10AM).getSeconds();

请注意,如果本地时间由于 DST 切换而不存在(例如在巴西移动到夏令时),Joda-Time 有时会导致异常为本地午夜创建一个瞬间。所以请小心处理在 Joda-Time 中创建瞬间。