日历设置年份问题

13

我尝试了下面这段代码:

Calendar c1 = Calendar.getInstance();
c1.set(Calendar.YEAR, 0);
c1.set(Calendar.DAY_OF_YEAR, 1);
Date d1 = c1.getTime();

Calendar c2 = Calendar.getInstance();
c2.setTime(d1);
c2.set(Calendar.YEAR, 2001);
c2.set(Calendar.DAY_OF_YEAR, 1);
System.out.println(c2.getTime().toString());

Calendar c3 = Calendar.getInstance();
c3.set(Calendar.YEAR, 2000);
c3.set(Calendar.DAY_OF_YEAR, 1);
Date d2 = c3.getTime();

Calendar c4 = Calendar.getInstance();
c4.setTime(d2);
c4.set(Calendar.YEAR, 2001);
c4.set(Calendar.DAY_OF_YEAR, 1);
System.out.println(c4.getTime().toString());

结果为:

Wed Jan 01 23:47:00 CET 2001
Mon Jan 01 23:47:00 CET 2001

出了什么问题?我不能用这种方式来设置年份吗?

2个回答

19
年份是相对于时代而言的。如果将年份设置为小于等于0的值,日历会自动更改时代(从公元后转为公元前或者从公元前转为公元后)以修正这个问题。这种行为在其他字段中更为常见,例如,如果您将月份设置为负数,年份会相应地递减。这些更正不是单独进行的,而是一次性完成的,通常在调用 getTime() 读取结果日期时进行。
Calendar c1 = Calendar.getInstance(); // August  16th, 2012 AD
c1.set(Calendar.YEAR, 0);             // August  16th,    0 AD
c1.set(Calendar.DAY_OF_YEAR, 1);      // January  1st,    0 AD
Date d1 = c1.getTime();               // January  1st,    1 BC (corrected)

Calendar c2 = Calendar.getInstance();
c2.setTime(d1);
c2.set(Calendar.YEAR, 2001);          // January  1st, 2001 BC
c2.set(Calendar.DAY_OF_YEAR, 1);
System.out.println(c2.getTime());     // prints "Wed Jan 01 05:35:00 CET 2001"
                                      // because 01/01/2001 BC was a Wednesday

因此,您不应将年份设置为2001,而应将其设置为-2000(因为根本不存在第0年)。或者,您可以明确设置时代:

c2.set(Calendar.ERA, GregorianCalendar.AD);

解决这个“bug”的另一种方法是在设置完整日期之前读取时间:

Calendar c1 = Calendar.getInstance(); // August  16th, 2012 AD
c1.set(Calendar.YEAR, 0);             // August  16th,    0 AD
c1.set(Calendar.DAY_OF_YEAR, 1);      // January  1st,    0 AD
c1.set(Calendar.YEAR, 2001);          // January  1st, 2001 AD
System.out.println(c1.getTime());     // prints the expected date

要输出日期的年代,您可以在SimpleDateFormat的模式中使用"G":

new SimpleDateFormat("E MMM dd HH:mm:ss z yyyy G").format(c2.getTime())
// "Wed Jan 01 05:35:00 CET 2001 BC"

3

在这两种情况下,在打印输出之前,您都将年份设置为2001。在这两种情况下,输出反映了那一年。您是否期望有不同的输出?


星期三与星期一。 此外,如果我将MILLISEC和SEC设置为0,并比较这两个日期,它们不会相等。最初我的目的是规范化DateTime对象的日期部分,以便仅比较时间部分。 - differenziale
哈哈!什么情况?是的,这个问题我没注意到。看起来你已经发现了一个bug。 - phatfingers
异常行为似乎与c1年份被设置为0(或负数年份)有关。当我尝试使用正数年份时,我只看到了正确的星期一结果。 - phatfingers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接