[英]JAVA: Weird behaviour when changing TimeZone of Calendar object without changing the Date/Time
我试图更改日历对象的时区,同时保持实际日期/时间,以便可以在更新的日历对象上调用getTimeInMilliseconds()。
我看着另一个问题 。 在这里,可接受的答案是单独设置新Calendar对象的每个字段。 但是,我能够通过简单地更改原始Calendar对象的副本的时区来使其工作。 奇怪的是,仅当我在重置timeZone之前对原始Calendar进行了一些修改时,此方法才有效。 以下示例说明了不一致之处。
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 PM UTC,相反,它对应的是当前日期/时间1/24 / 2014 2:33:58 MTN)。 有人可以告诉我这是怎么回事吗?
编辑:刚刚更新了一些格式。
设置时区不能像设置字段那样工作。 设置字段时,将重新计算内部的毫秒数以匹配字段。 设置时区时,将重新计算字段,以使毫秒数保持不变! (也就是说,当您将clanedar评估为2:00 PM峰并将其设置为UTC时,它不会计算代表2PM UTC的毫秒数,因此会将时间更改为9PM。)
现在这是横set
的地方,当您有一个待处理的set
(或在您的情况下add
)时,告诉Calendar重新计算毫秒数(由add
启用)的标志优先于指示是否重新计算文本字段的标志。关闭毫秒(由setTimeZone
打开)
因此,方案1日历具有文本值:
2015年1月24日,星期六UTC,并且因为add
被称为标志,说“基于“人类”值重新计算毫秒”被打开,它为您提供了您期望的#。
方案2日历具有文本值:
2015年1月24日,星期六UTC,但表示重新计算毫秒数的标志未打开,因此将设置时区设置为“基于毫秒重新计算“人类值”的标志”打开,并且它将更改为晚上9点。
如果将代码更改为:
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));
}
您将看到两者之间的行为一致,因为调用getTime()会清除该标志,以便在设置时区之前重新计算毫秒。
现在您知道为什么股票对此类问题的答案是“ omg use jodatime”!
获得您期望发生的事情的“安全”方法是:
protected String getUTCMilliseconds(Calendar cal) {
Calendar utcCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
utcCal.set(Calendar.YEAR, cal.get(Calendar.YEAR));
utcCal.set(Calendar.DAY_OF_YEAR, cal.get(Calendar.DAY_OF_YEAR));
utcCal.set(Calendar.HOUR_OF_DAY, cal.get(Calendar.HOUR_OF_DAY));
utcCal.set(Calendar.MINUTE, cal.get(Calendar.MINUTE));
utcCal.set(Calendar.SECOND, cal.get(Calendar.SECOND));
utcCal.set(Calendar.MILLISECOND, cal.get(Calendar.MILLISECOND));
return String.valueOf(utcCal.getTimeInMillis());
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.