格里高利日历的奇怪行为

2022-09-04 02:05:25

我刚刚在格里高利日历课上遇到了一个奇怪的行为,我想知道我是否真的在做坏事。

仅当初始化日期的月份的实际最大值大于我要将日历设置为的月份时,才会附加。

下面是示例代码:

    // today is 2010/05/31  
    GregorianCalendar cal = new GregorianCalendar();

    cal.set(Calendar.YEAR, 2010);
    cal.set(Calendar.MONTH, 1); // FEBRUARY

    cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
    cal.set(Calendar.HOUR_OF_DAY, cal.getActualMaximum(Calendar.HOUR_OF_DAY));
    cal.set(Calendar.MINUTE, cal.getActualMaximum(Calendar.MINUTE));
    cal.set(Calendar.SECOND, cal.getActualMaximum(Calendar.SECOND));
    cal.set(Calendar.MILLISECOND, cal.getActualMaximum(Calendar.MILLISECOND));

    return cal.getTime(); // => 2010/03/03, wtf

我知道这个问题是由日历初始化日期是一个31天月份(may)的事实引起的,这与设置为2月(28天)的月份混淆了。修复很容易(在设置年份和月份之前将day_of_month设置为1),但我想知道这真的是想要的行为。有什么想法吗?


答案 1

它获取当前日期/时间的实际最大值。5月有31天,比2月28日多3天,因此它将转移到3月3日。

您需要在获取/创建 Calendar#clear() 后调用它:

GregorianCalendar cal = new GregorianCalendar();
cal.clear();
// ...

这导致:

Sun Feb 28 23:59:59 GMT-04:00 2010

(根据我的时区,这是正确的)

正如其中一个答案所说,和是史诗般的失败。在执行密集的日期/时间操作时,请考虑 JodaTimejava.util.CalendarDate


答案 2

是的,这就是它的工作方式。如果您从具有精确日期的开始,并通过使其不一致来修改它,那么您不应该信任您获得的结果。GregorianCalendar

根据有关它的文档指出:getActualMaximum(..)

例如,如果此实例的日期是 2004 年 2 月 1 日,则DAY_OF_MONTH 字段的实际最大值为 29,因为 2004 年是闰年,如果此实例的日期是 2005 年 2 月 1 日,则为 28。

所以它应该有效,但你必须用一致的价值观来喂养它。2010 年 2 月 31 日不正确,应用依赖于日期值(如 )的内容不起作用。它应该如何自行修复它?通过决定那个月是错误的?还是那天错了?getActualMaximum

顺便说一句,正如每个人总是说的那样,使用JodaTime。:)


推荐