夏时制更改期间的Java Calendar.roll和CST

夏时制更改期间的Java Calendar.roll和CST,java,datetime,timezone,dst,Java,Datetime,Timezone,Dst,我想知道Calendar.roll是否遵守其javadoc合同: 运行以下代码段 final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("CST")); cal.setTimeInMillis(1457928024812l); System.out.println(cal.getTime()); cal.roll(Calendar.HOUR_OF_DAY, true); System

我想知道Calendar.roll是否遵守其javadoc合同:

运行以下代码段

    final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("CST"));
    cal.setTimeInMillis(1457928024812l);

    System.out.println(cal.getTime());
    cal.roll(Calendar.HOUR_OF_DAY, true);
    System.out.println(cal.getTime());
yiels输出如下:

Sun Mar 13 23:00:24 CDT 2016
Sun Mar 13 23:00:24 CDT 2016
2016年3月13日是凌晨2点(从CST改为CDT)的夏令时。 滚动的javadoc声明滚动“添加了一个时间单位”,这里没有添加时间单位。 这是该方法的预期行为吗

编辑:


我报告这是一个错误。有关更多信息,请参阅相应OpenJDK票证的链接:

这似乎是
roll
方法中的实际错误。好发现

几点注意:

  • 我必须使用一个
    SimpleDateFormat
    来获得您显示的确切结果,因为只要调用
    getTime
    就会得到一个
    Date
    对象,该对象在本地时区打印

  • 最好使用
    America/Chicago
    而不是
    CST
    ,但这不是原因

  • 对于任何常规日期,第23小时应在同一天变为第0小时。如果您只想增加一小时,那么使用
    add
    而不是
    roll
    。看见
    add
    方法似乎工作正常

  • 在春季提前过渡的那天,一天只有23个小时。
    roll
    方法似乎考虑到了这一点,即使它没有跨越实际的转换(在这个时区,当时钟跳到3:00时,转换发生在接近2:00时)。如您所示,它将小时设置为
    23
    ,这比它应该设置的
    0
    早一个小时

  • 在后退过渡的那天,一天有25个小时。同样,
    roll
    方法尝试考虑到这一点,将小时设置为
    1
    ,而不是
    0
    ,即使它没有穿过实际的转换(当时钟移回1:00时,在该时区接近2:00时再次发生)

我做了一个快速搜索,看看这是否已经被报道在任何地方,并没有找到太多。也许你应该

<>我也会补充说,你应该考虑使用java 7或更早的版本,对于java 8或更新版本。

如:

  • 大陆/地区
    格式中使用a。避免使用既不独特也不标准的3-4字母代码
  • 使用Java 8及更高版本中内置的框架。看见避免使用旧的日期时间类java.util.date/.Calendar
一个是时间线上的一个有决心的时刻。应用时区()以获取一个时间间隔

转储到控制台

System.out.println ( "input: " + input + " |  instant: " + instant + " | zoneId: " + zoneId + " | zdt: " + zdt + " | zdtHourLater: " + zdtHourLater );
System.out.println ( "zdtBeforeTwoAm: " + zdtBeforeTwoAm + " |  zdtBeforeTwoAmPlus: " + zdtBeforeTwoAmPlus );
System.out.println ("zdtTwoAm: " + zdtTwoAm );
输入:1457928024812 |即时:2016-03-14T04:00:24.812Z |地区ID:美国/芝加哥| zdt:2016-03-13T23:00:24.812-05:00[美国/芝加哥]| zdtHourLater:2016-03-14T00:00:24.812-05:00[美国/芝加哥]

因此,java.time中没有这样的问题。加上一个小时,从13日晚上11点到14日午夜刚过,就像预期的那样在午夜移动

夏时制(DST) DST处理得当

跨越DST转换 如预期的那样,从凌晨1:59增加一个小时,时钟上的两个小时将跳到凌晨3:59

ZonedDateTime zdtBeforeTwoAm = ZonedDateTime.of ( 2016, Month.MARCH.getValue ( ), 13, 1, 59, 0, 0, zoneId );
ZonedDateTime zdtBeforeTwoAmPlus = zdtBeforeTwoAm.plusHours ( 1 );
转储到控制台

System.out.println ( "input: " + input + " |  instant: " + instant + " | zoneId: " + zoneId + " | zdt: " + zdt + " | zdtHourLater: " + zdtHourLater );
System.out.println ( "zdtBeforeTwoAm: " + zdtBeforeTwoAm + " |  zdtBeforeTwoAmPlus: " + zdtBeforeTwoAmPlus );
System.out.println ("zdtTwoAm: " + zdtTwoAm );
Zdtbefortwoam:2016-03-13T01:59-06:00[美国/芝加哥]| Zdtbefortwoamplus:2016-03-13T03:59-05:00[美国/芝加哥]

要求凌晨2点 要求凌晨2点是无效的(没有这样的时间)。因此java.time会自动移动到一个有效的等效值,即凌晨3点

ZonedDateTime zdtTwoAm = ZonedDateTime.of ( 2016, Month.MARCH.getValue ( ), 13, 2, 0, 0, 0, zoneId );
转储到控制台

System.out.println ( "input: " + input + " |  instant: " + instant + " | zoneId: " + zoneId + " | zdt: " + zdt + " | zdtHourLater: " + zdtHourLater );
System.out.println ( "zdtBeforeTwoAm: " + zdtBeforeTwoAm + " |  zdtBeforeTwoAmPlus: " + zdtBeforeTwoAmPlus );
System.out.println ("zdtTwoAm: " + zdtTwoAm );
ZDTWOAM:2016-03-13T03:00-05:00[美国/芝加哥]


谢谢你,马特。关于
America/Chicago
事件,我用
CST
简单地重现了这个问题。它发生在具有默认时区的服务器上,使用一个简单的
Calendar.getInstance()