日历日期Java,跳过一个小时2014-02-16



我在使用Date和Calendar类处理模拟商店到达时间的指数分布时发现了这种有趣的行为(学术工作)。代码非常简单,如下所示。假设"this.currentDate"是"2014年2月15日08:00:00 BRST"。如果我将时间向前移动24小时(参数iSeconds=86.400),应该返回什么?预期的字符串是"2014-02-16 08:00:00",但时间缩短了1小时,结果是"2014-03-16 07:00:00",我想知道是否有人能解释为什么我的一个小时被"偷走"。没什么大不了的,但由于我的下一次到达时间取决于前一次,这让我的时间基线也变了一个小时。

我以为可能是TZ的问题,但天哪,我在2月中旬刚搬了24小时。

public  String shiftTimeStamp( int iSeconds)
{
 Calendar cal = Calendar.getInstance();     
     cal.setTime(this.currentDate);
     cal.add(Calendar.SECOND, iSeconds);
     this.currentDate = cal.getTime();
     String sTS = new SimpleDateFormat(SCSimLabels.DATE_TS_FORMAT).format(this.currentDate);
return sTS;
}

注意:夏令时问题:)BRT<-->BRST tz

我的解决方法:我只想用一个信标来引导因到达时间间隔而导致的时间跳跃,我对这种日历的特殊性不感兴趣,所以当我需要转移到第二天的第一个工作时间时,我只会强制将时间定为1天轮班后的08:00:00。它就像一个符咒:)

Calendar cal = Calendar.getInstance();
cal.setTime(this.currentDate);
cal.add(Calendar.DATE, 1);
String sDate = (new SimpleDateFormat("yyyy-MM-dd 08:00:00")).format(cal.getTime());
Date newDate =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(sDate);   
this.currentDate = newDate;

将格式调用更改为:

return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z").format(this.currentDate);

查看格式化调用使用的时区。我敢打赌,对.add()的调用是在修改Calendar对象的时区,因为它跨越了标准时间/夏令时边界。

如果是这种情况,您可以尝试在.add调用后将Calendar对象的Calendar.DAY、1或简单的.setTimeZone(…)添加回原始时区。

避免遗留日期时间类

您正在使用麻烦的旧日期时间类,这些类现在是遗留的,已被java.time类取代。

使用java.time

如果您希望使用没有任何时区或UTC偏移的通用24小时工作日,请使用LocalDateTime类。如果始终希望在上午8点开始,请指定LocalTime

LocalDate ld = LocalDate.of( 2014 , Month.FEBRUARY , 15 ) ;
LocalTime lt = LocalTime.of( 8 , 0 ) ; // Specify hour in 24-hour clock, 0-23.
LocalDateTime ldt = LocalDateTime.of( ld , lt );

将您的24小时跨度表示为Duration

Duration d = Duration.ofHours( 24 );
LocalDateTime ldtLater = ldt.plus( d );

如果您想通过某个地区特定的挂钟时间来处理时间线上的特定时刻,请指定ZoneId以获得ZonedDateTime

ZoneId z = ZoneId.of( "America/Sao_Paulo" ) ;
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;
ZonedDateTime zdtLater = zdt.plus( d );

请注意,将24小时添加到ZonedDateTime是,而不是与添加一天相同。正如你所学到的,夏令时(DST)等异常情况意味着一天可能长达23、24或25小时,甚至其他时间。因此,如果您想添加一天,并让java.time应用其逻辑在一天中的适当时间到达,同时考虑DST等异常情况,请添加,而不是小时

ZonedDateTime zdtLater = zdt.plusDays( 1 );  

或者添加一整天的Period,而不是24小时的Duration

Period p = Period.ofDays( 1 );
ZonedDateTime zdtLater = zdt.plus( p );

关于java.time

java.time框架是在java 8及更高版本中构建的。这些类取代了诸如java.util.DateCalendar和&CCD_ 10。

JodaTime项目现在处于维护模式,建议迁移到java.Time类。

要了解更多信息,请参阅Oracle教程。并在Stack Overflow中搜索许多示例和解释。规范是JSR310。

从哪里获得java.time类?

  • Java SE 8Java SE 9及更高版本
    • 内置
    • 标准Java API的一部分,带有捆绑实现
    • Java 9添加了一些小功能和修复程序
  • Java SE 6Java SE 7
    • 大部分java.time功能都是向后移植到Java6&7英寸ThreeTen背包
  • 安卓
    • ThreeTenABP项目专门为安卓系统改编了ThreeTen Backport(如上所述)
    • 请参阅如何使用ThreeTenABP…

ThreeTen Extra项目通过附加类扩展java.time。这个项目是将来可能添加到java.time的试验场。您可以在这里找到一些有用的类,如IntervalYearWeekYearQuarter等等。

最新更新