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



我想知道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指出roll"增加了一个时间单位",这里没有添加时间单位。这是此方法的预期行为吗?

编辑:

我将此报告为错误。有关更多信息,这里是相应 OpenJDK 票证的链接:https://bugs.openjdk.java.net/browse/JDK-8152077

似乎是roll方法中的一个实际错误。 不错的发现!

几点注意事项:

  • 我不得不使用SimpleDateFormat来获得您显示的确切结果,因为只需调用getTime就会给出一个以本地时区打印的Date对象。

  • 最好使用 America/Chicago 而不是 CST ,但这不是造成这种情况的原因。

  • 对于任何常规日期,它滚动第 23 小时应在同一天转到第 0 小时。 如果您只想递增一小时,请使用 add 而不是 roll 。 请参阅添加与滚动。 add方法似乎工作正常。

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

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

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

我还要补充一点,您可能应该考虑在Java 7或更早版本中使用Joda Time,在Java 8或更高版本中使用java.time Joda Time。

正如Matt Johnson的回答所说:

  • 使用continent/region格式的正确时区名称。避免使用既不唯一也不标准化的 3-4 个字母代码。
  • 使用内置于 Java 8 及更高版本中的 java.time 框架。请参阅教程。避免使用旧的日期时间类 java.util.Date/。日历。

Instant是时间轴上以纳秒分辨率表示的时刻。应用时区 ( ZoneId ) 以获得ZonedDateTime

Long input = 1457928024812L;
Instant instant = Instant.ofEpochMilli ( input );
ZoneId zoneId = ZoneId.of ( "America/Chicago" );
ZonedDateTime zdt = ZonedDateTime.ofInstant ( instant, zoneId );
ZonedDateTime zdtHourLater = zdt.plusHours ( 1 );

转储到控制台。

System.out.println ( "input: " + input + " |  instant: " + instant + " | zoneId: " + zoneId + " | zdt: " + zdt + " | zdtHourLater: " + zdtHourLater );

输入: 1457928024812 | 即时: 2016-03-14T04:00:24.812Z |区域 ID: 美国/芝加哥 |ZDT: 2016-03-13T23:00:24.812-05:00[美国/芝加哥] |zdtHour稍后: 2016-03-14T00:00:24.812-05:00[美国/芝加哥]

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

夏令时 (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 ( "zdtBeforeTwoAm: " + zdtBeforeTwoAm + " |  zdtBeforeTwoAmPlus: " + zdtBeforeTwoAmPlus );

zdt之前凌晨两点: 2016-03-13T01:59-06:00[美国/芝加哥] | zdt之前两个AmPlus: 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 ("zdtTwoAm: " + zdtTwoAm );

zdtTwoAm: 2016-03-13T03:00-05:00[美国/芝加哥]

相关内容

  • 没有找到相关文章

最新更新