GregorianCalendar在2014年1月30日为“亚洲/新加坡”TimeZone和系统日期提供意外结果

时间:2014-02-19 12:52:39

标签: java

我正面临与GregorianCalendar相关的问题。

Prerequisit:  系统timeZone是:“亚洲/新加坡”  系统时间是:2014年1月30日

执行代码:

 Calendar cal = new GregorianCalendar();
 TimeZone tz = TimeZone.getTimeZone("Asia/Singapore");
 cal.setTimeZone(tz);
 cal.set(Calendar.MONTH, 1);//1 is equivalent to Feb
 cal.get(Calendar.YEAR);
 cal.set(Calendar.YEAR, 2014);
 cal.get(Calendar.DAY_OF_MONTH);
 cal.set(Calendar.DAY_OF_MONTH, 5);
 Date dte=cal.getTime();

实际结果: 2014年3月5日

预期成果: 2014年2月5日

但是如果我按顺序改变执行相同的代码,则会产生正确的值:

 Calendar cal = new GregorianCalendar();
 TimeZone tz = TimeZone.getTimeZone("Asia/Singapore");
 cal.setTimeZone(tz);
 cal.get(Calendar.DAY_OF_MONTH);
 cal.set(Calendar.DAY_OF_MONTH, 5);
 cal.set(Calendar.MONTH, 1);//1 is equivalent to Feb
 cal.get(Calendar.YEAR);
 cal.set(Calendar.YEAR, 2014);

它给出了正确的结果

有人可以帮助我知道这个的根本原因吗?

1 个答案:

答案 0 :(得分:1)

在1月30日运行代码时,这将是您日历的初始状态。然后cal.set(Calendar.MONTH, 1);将日历设置为2月30日。 致电cal.get(DAY_OF_MONTH)时,将重新计算日历的内部状态以获得正确的日期。因此cal.isLenient()为真,所以2月30日将被转换为3月2日。 然后将日期设置为30将导致3月30日。

尝试在创建日历后添加cal.setLenient(false),然后查看代码的第一个版本是如何失败的......

要修复代码,请在日历处于中间状态时删除get cal.get() - 语句,以避免过早重新计算。

编辑:添加了关于cal.get()

的部分内容