JAVA:在不更改日期/时间的情况下更改Calendar对象的TimeZone时的奇怪行为

时间:2014-01-24 21:43:26

标签: java datetime calendar timezone datetime-conversion

我正在尝试更改日历对象的时区,同时保持实际日期/时间,以便我可以在更新的日历对象上调用getTimeInMilliseconds()。

我看了this other question。这里,接受的答案是单独设置新Calendar对象的每个字段。但是,我只需更改原始Calendar对象副本的时区即可使其工作。奇怪的是,这只有在我重置timeZone之前对原始日历进行一些修改时才有效。以下示例说明了不一致性。

public void TestCalendar()
{
   Calendar nextYear = Calendar.getInstance();
   nextYear.add(Calendar.YEAR, 1);
   log.info("Next Year: {}", getUTCMilliseconds(nextYear));

   Calendar now = Calendar.getInstance();
   log.info("Now: {}", getUTCMilliseconds(now));
}

protected String getUTCMilliseconds(Calendar cal)
{
   // Create a new calendar so we don't modify input
   Calendar expectedDbTime = (Calendar) cal.clone();
   // Change the TimeZone the contained date is interpreted in
   expectedDbTime.setTimeZone(TimeZone.getTimeZone("UTC"));
   // Return millisecond value of this date in the UTC timezone
   return String.valueOf(expectedDbTime.getTimeInMillis());
}

我在2015年1月24日下午2:33运行了这个程序,得到了以下输出:

Next Year: 1422110038529 //(Corresponding UTC Date: Sat Jan 24 2015 2:33:58 PM)
Now: 1390599238531 //(Corresponding UTC Date: Fri Jan 24 2014 9:33:58 PM)

如您所见,nextYear按预期打印,但下一行不是 正如预期的那样(它应该对应于UTC时间的1/24/2014 2:33:58,相反,它对应于 当前日期/时间是2014年1月24日2:33:58 MTN)。有人能告诉我这里发生了什么吗?

编辑:刚刚更新了一些格式。

1 个答案:

答案 0 :(得分:2)

设置时区不像设置字段那样有效。设置字段时,将重新计算内部的毫秒数以匹配字段。设置时区时,将重新计算字段,以使毫秒数保持不变! (也就是说,如果您将clanedar评估为下午2:00并将其设置为UTC,则它不会计算代表2PM UTC的毫秒数,而是将时间更改为晚上9点。)

现在,当你有一个挂起的set(或你的add)时,这个标志会告诉Calendar重新计算毫秒数(由{{1}打开) })优先于告诉我是否重新计算毫秒级文本字段的标志(由add启用)

所以方案1日历有文本值:

2015年1月24日星期六下午2:33:58 UTC并且因为setTimeZone被称为“基于'人'值重新计算毫秒数”的标志已打开,它会为您提供您期望的#。

场景2日历具有文本值:

2015年1月24日星期六下午2:33:58 UTC,但是重新计算毫秒数的标志未打开,因此设置时区打开的标志为“基于毫秒重新计算'人类值'”是打开并将其更改为晚上9点。

如果您将代码更改为:

add

你会看到两者之间的行为一致,因为调用getTime()会清除标志,以便在设置时区之前重新计算毫秒数。

现在您知道为什么股票回答这样的问题是'omg use jodatime'!

获得您期望发生的事情的“安全”方式是:

public void TestCalendar() {
    Calendar nextYear = Calendar.getInstance();
    nextYear.add(Calendar.YEAR, 1);
    nextYear.getTime();
    log.info("Next Year: {}", getUTCMilliseconds(nextYear));

    Calendar now = Calendar.getInstance();
    log.info("Now: {}", getUTCMilliseconds(now));
}