How to handle dates when the input dates are in the transition period from PDT to PST?

前端 未结 2 1297
没有蜡笔的小新
没有蜡笔的小新 2020-12-12 00:49

I am calling an API which takes two dates as input.The API checks if the difference between the two date is greater than 60 min, then it throws an exception.My input dates a

相关标签:
2条回答
  • 2020-12-12 01:30

    Neither SimpleDateFormat nor the underlying Calendar specifies what happens when parsing a datetime string without timezone for a time in the overlapping hour between daylight savings time and standard time.

    You have observed that it will return the later time, i.e. it seems to prefer standard over daylight savings time. But, the behavior is undefined, so...

    The new java.time classes do however specify exactly what happens, and how to choose the other "hour" of the overlap.

    In the new API, since your datetime string is without timezone, you'd likely first parse using LocalDateTime, then apply time zone to get a ZonedDateTime, e.g.

    LocalDateTime ldtEnd = LocalDateTime.parse("2016-11-06T01:56:01");
    ZonedDateTime zdtEnd = ldtEnd.atZone(ZoneId.of("America/Los_Angeles"));
    // zdtEnd is now: 2016-11-06T01:56:01-07:00[America/Los_Angeles]
    

    To see the overlap, you can try adding an hour:

    ZonedDateTime zdtEnd2 = zdtEnd.plusHours(1);
    // zdtEnd2 is now: 2016-11-06T01:56:01-08:00[America/Los_Angeles]
    

    The behavior is well-defined, see javadoc of atZone():

    In most cases, there is only one valid offset for a local date-time. In the case of an overlap, where clocks are set back, there are two valid offsets. This method uses the earlier offset typically corresponding to "summer".

    In the case of a gap, where clocks jump forward, there is no valid offset. Instead, the local date-time is adjusted to be later by the length of the gap. For a typical one hour daylight savings change, the local date-time will be moved one hour later into the offset typically corresponding to "summer".

    To obtain the later offset during an overlap, call ZonedDateTime.withLaterOffsetAtOverlap() on the result of this method. To throw an exception when there is a gap or overlap, use ZonedDateTime.ofStrict(LocalDateTime, ZoneOffset, ZoneId).

    As you can see, it will always return the earlier time in an overlap, which is opposite of the observed behavior of SimpleDateFormat. If you want the later time in an overlap, call withLaterOffsetAtOverlap().

    If you don't want to rely on documented default, you can always be explicit:

    ZoneId PT = ZoneId.of("America/Los_Angeles");
    
    LocalDateTime ldtStart = LocalDateTime.parse("2016-11-06T00:57:01");
    ZonedDateTime zdtStartEarly = ldtStart.atZone(PT).withEarlierOffsetAtOverlap();
    ZonedDateTime zdtStartLater = ldtStart.atZone(PT).withLaterOffsetAtOverlap();
    System.out.println(zdtStartEarly); // 2016-11-06T00:57:01-07:00[America/Los_Angeles]
    System.out.println(zdtStartLater); // 2016-11-06T00:57:01-07:00[America/Los_Angeles]
    
    LocalDateTime ldtEnd = LocalDateTime.parse("2016-11-06T01:56:01");
    ZonedDateTime zdtEndEarly = ldtEnd.atZone(PT).withEarlierOffsetAtOverlap();
    ZonedDateTime zdtEndLater = ldtEnd.atZone(PT).withLaterOffsetAtOverlap();
    System.out.println(zdtEndEarly); // 2016-11-06T01:56:01-07:00[America/Los_Angeles]
    System.out.println(zdtEndLater); // 2016-11-06T01:56:01-08:00[America/Los_Angeles]
    

    As you can see, for the 00:57 time, it makes no difference, because that time is not in the overlap hour.

    0 讨论(0)
  • 2020-12-12 01:41

    What you can do here get the difference between the 2 dates using timezone offset. something like below

    private int getDSTdifferenceDateAdjustment(Date startDate, Date endDate, TimeZone timeZone)
    {
        if (startDate == null || endDate == null) return 0;
        int baseOffset = timeZone.getOffset(startDate.getTime());
        int newOffSet = timeZone.getOffset(endDate.getTime());
    
        return (newOffSet - baseOffset);
    }
    

    Have something like this in your method

    int dstDifference = getDSTdifferenceDateAdjustment(startdate, enddate, TimeZone.getDefault());
    // The dstDifference will get in the negative, so we are adding to the dateRange variable
    dateRange += dstDifference;
    

    Try this one and even check when the DST starts next year. Mostly this will work in all these cases

    0 讨论(0)
提交回复
热议问题