Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
224 views
in Technique[技术] by (71.8m points)

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

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 are startDate=11-06-2016T00:57:01 and endDate=11-06-2016T01:56:01.These two dates are saved in java.util.Date object. Now the issue is though the two dates have a difference of 59 min which is less than 60 min, still the API throws exception.Looks like this isssue is due to DayLightSaving.On Nov 6,once 2 am is reached , DayLightSaving ends (PDT time zone ends), time is moved backward by 1 hr due to which time again become 1 am but in PST time zone now.This means on Nov 6 , there would be 1-2 am twice one in PDT and one in PST zone. When this API is called on NOV 7, the time zone would be PST.So when the two dates are passed without the timezone specified, it takes the startDate in PDT zone and enddate in PST zone.Since PDT and PST itself have a difference of 1 hour, this would get added to the 59 min differnce and exception is being thrown. How to handle this case when the input dates are in the transition period from PDT to PST?

sample code

SimpleDateFormat formatter1 = new SimpleDateFormat("MM-dd-yyyy hh:mm:ss");
String start="11-06-2016 00:57:01";
String end ="11-06-2016 01:56:01";
Date startdate = formatter1.parse(start);
Date enddate = formatter1.parse(end);
System.out.println("startDate is :"  + startdate);
System.out.println("endDate is :"  +enddate);
long dateRange = enddate.getTime() - startdate.getTime();
//if the difference between the two dates is > than 60 min i.e  3600000 ms, then throw exception.
System.out.println(dateRange);
if (dateRange > (60 * 60 * 1000)){
    throw new Exception("Date time range cannot be greater than 60 minutes.(calculated using millisecond difference)");
}

Output

[Date Range is = 7140000
Exception in thread "main" java.lang.Exception: Date time range cannot be greater than 60 minutes.(calculated using millisecond difference).
    at Datetest.main(Datetest.java:28)][1]

The above snippet throws exception when called in PST time zone.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...