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

我正在调用一个API,它接受两个日期作为输入.API检查两个日期之间的差异是否大于60分钟,然后它抛出exception。我的输入日期是startDate = 11-06-2016T00:57:01和endDate = 11-06-2016T01:56:01。这两个日期保存在java.util.Date对象中。 现在问题是虽然这两个日期的差异为59分钟,小于60分钟,但API仍会引发exception。看起来像这样是因为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分钟的差异,并抛出exception。 当输入日期处于从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 ie 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时区中调用时,上面的代码段会引发exception。

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:

在大多数情况下,本地日期时间只有一个有效偏移量。 在重叠的情况下 ,时钟被设置回来,有两个有效的偏移。 该方法使用通常对应于“夏天”的较早偏移

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

在重叠期间获得后一个偏移量对此方法的结果调用ZonedDateTime.withLaterOffsetAtOverlap() 。 要在存在间隙或重叠时抛出exception,请使用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时间,它没有任何区别,因为该时间不在重叠小时内。

你在这里可以做的是使用时区偏移来获得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明年何时开始。 大多数情况下,这将适用于所有这些情况