如何处理输入日期在从PDT到PST的过渡期间的日期?

时间:2016-12-14 05:59:45

标签: java

我正在调用一个API,它接受两个日期作为输入.API检查两个日期之间的差异是否大于60分钟,然后它抛出异常。我的输入日期是startDate = 11-06-2016T00:57 :01和endDate = 11-06-2016T01:56:01。这两个日期保存在java.util.Date对象中。 现在的问题是两个日期的差异为59分钟,小于60分钟,但仍然会抛出异常。看起来像这样是因为DayLightSaving.On 11月6日,一旦达到凌晨2点,DayLightSaving结束(PDT)时区结束),时间向后移动1小时,因为时间再次变为凌晨1点,但现在在PST时区。这意味着11月6日凌晨1点到凌晨2点,PDT两次,PST区域一次。 当在NOV 7上调用此API时,时区将是PST.So。当两个日期在没有指定时区的情况下通过时,它将在PDT区域中使用startDate并在PST区域中结束。因为PDT和PST本身有区别1小时,这将加到59分钟的差异,并抛出异常。 当输入日期处于从PDT到PST的过渡期时,如何处理这种情况?

示例代码

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

输出

[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]

上述代码段在PST时区中调用时会引发异常。

2 个答案:

答案 0 :(得分:1)

SimpleDateFormat和基础Calendar都没有指定在夏令时和标准时间之间的重叠小时内解析没有时区的日期时间字符串时会发生什么。

您已经观察到它将返回较晚的时间,即它似乎更喜欢标准而不是夏令时。但是,行为是未定义的,所以......

然而,新的java.time类确实指明了发生了什么,以及如何选择其他"小时"重叠。

在新的API中,由于您的日期时间字符串没有时区,因此您可能首先使用LocalDateTime进行解析,然后应用时区来获取ZonedDateTime,例如

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]

要查看重叠,您可以尝试添加一小时:

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

行为定义明确,请参阅atZone()的javadoc:

  

在大多数情况下,本地日期时间只有一个有效偏移量。 在重叠的情况下,在设置时钟的情况下,有两个有效的偏移量。 此方法使用之前的偏移量,通常对应于" summer"

     

在间隙的情况下,时钟向前跳跃,没有有效的偏移。而是将本地日期时间调整为稍后的间隙长度。对于典型的一小时夏令时更改,本地日期时间将在一小时后移动到通常对应于"夏天"的偏移量。

     

要在重叠期间获得后期偏移调用此方法的结果ZonedDateTime.withLaterOffsetAtOverlap() 。要在存在间隙或重叠时抛出异常,请使用ZonedDateTime.ofStrict(LocalDateTime, ZoneOffset, ZoneId)

正如您所看到的,它总是会在重叠时返回之前的时间,这与SimpleDateFormat的观察行为相反。如果您希望稍后时间重叠,请致电withLaterOffsetAtOverlap()

如果您不想依赖记录的默认值,您可以始终明确:

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]

正如您所看到的,对于00:57时间,它没有任何区别,因为该时间不在重叠小时内。

答案 1 :(得分:0)

您可以在此处使用时区偏移来获取2个日期之间的差异。类似下面的内容

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

在你的方法中有类似的东西

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

尝试这个,甚至检查DST明年何时开始。大多数情况下,这将适用于所有这些情况