我想知道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());
以下输出:
Sun Mar 13 23:00:24 CDT 2016
Sun Mar 13 23:00:24 CDT 2016
2016年3月13日是凌晨2点(从CST到CDT)的夏令时变化。 卷状态的javadoc滚动“添加单个时间单位”,此处不添加任何时间单位。 这是该方法的预期行为吗?
编辑:
我将此报告为错误。有关更多信息,请参阅相应OpenJDK票证的链接:https://bugs.openjdk.java.net/browse/JDK-8152077
答案 0 :(得分:2)
这似乎是roll
方法中的实际错误。很好找!
几点说明:
我必须使用SimpleDateFormat
来获得您展示的确切结果,因为只需调用getTime
即可在本地时区打印一个Date
对象。< / p>
最好使用America/Chicago
而不是CST
,但这不是原因。
对于任何常规日期,第23小时滚动应该在同一天的0小时。如果您只想增加一小时,请使用add
代替roll
。见add vs roll。 add
方法似乎工作正常。
在春季前进过渡当天,一天只有23个小时。 roll
方法似乎考虑到了这一点,即使它没有越过实际转换(当时钟跳到3:00时,这个时区接近2:00)。如您所示,它将小时设置为23
,这是它应该设置的0
之前一小时。
在回归过渡当天,当天有25个小时。同样,roll
方法尝试将此考虑在内,将小时设置为1
而不是0
,即使它没有超过实际转换(再次发生在接近凌晨2点)这个时区,当时钟回到1点时。
我做了一个快速搜索,看看是否已经在任何地方进行了报道并且没有找到多少。也许你应该report it。
我还要补充一点,您应该考虑将Joda Time用于Java 7或更早版本,将java.time
用于Java 8或更高版本。
答案 1 :(得分:1)
正如the Answer by Matt Johnson所说:
continent/region
格式的proper time zone name。避免使用既不唯一也不标准化的3-4字母代码。 Instant
是UTC时间轴上nanosecond分辨率的时刻。应用时区(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 | zoneId:America / Chicago | zdt:2016-03-13T23:00:24.812-05:00 [美国/芝加哥] | zdtHourLater:2016-03-14T00:00:24.812-05:00 [美国/芝加哥]
所以,java.time中没有这样的问题。正如预期的那样,从13日晚上11点到14日午夜,加上一小时的午夜时间。
正确处理DST。
从凌晨1点59分开始加1小时,按时间顺序跳2小时到凌晨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 );
zdtBeforeTwoAm:2016-03-13T01:59-06:00 [美国/芝加哥] | zdtBeforeTwoAmPlus:2016-03-13T03:59-05:00 [美国/芝加哥]
要求凌晨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 [美国/芝加哥]