Joda Time getSecondOfDay on DST switch day

2019-07-29 00:26发布

问题:

I'm getting strange behavior from Joda Time when trying to get the seconds since midnight on a DST switch day.

My code:

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);
    }
}

Output:

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

(translation from German: MEZ = CET, MESZ = CEST)

As you can see, Oct 30 is the DST switch day. The switch occurs between 2 and 3 AM. If I'm not mistaken, summer time is UTC+2 and winter time is UTC+1, so at 3 AM, clocks are turned back to 2 AM.

Now this obviously implies an overlap for 2-3, but my test uses 1 AM and 10 AM, which should be unambiguous. I'd expect the instant at Oct 30, 1 AM CEST to be 3600 seconds since midnight, and the instant at Oct 30, 10 AM CET to be 39600 seconds since midnight (11 hours). But getSecondOfDay() returns 10 hours since midnight.

The only implication I could imagine (besides a stupid error) is that getSecondOfDay() does not actually return the seconds since midnight, but something else. However, every example I found on the net seems to imply that it does return the number of seconds since midnight. There's no DST-related redefinition of "midnight" that I know of, either.

Why do I get these results? What is getSecondOfDay() meant to do in this situation? What else should I do to get the number of seconds since midnight?

回答1:

The field SECOND_OF_DAY is inherently based on the local timeline. This means, it does not count the physically elapsed SI- or POSIX-seconds since midnight but only represents the nominal count of clock strikes as displayed on a wall clock which always has 24 hours/strikes per day-night-cycle ignoring any DST-issue. Or another description: Just imagine that this field displays the position of the second hand on the clock face.

But you can determine the physically elapsed seconds in another way. The class DateTime is an instant, so you can first determine the instant for midnight and then the second instant for let's say at 10 AM. Then you apply this expression:

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

Note that Joda-Time sometimes causes an exception to create an instant for local midnight if this local time does not exist due to DST-switch (like in Brazil when moving to summer time). So please handle the creation of instants in Joda-Time with care.