2月java.util.Calendar的一个奇怪的行为

时间:2013-01-30 13:36:25

标签: java calendar

我遇到了来自java.util.Calendar的奇怪行为:

import static org.junit.Assert.*;
import org.junit.Test;

import java.util.Calendar;

public class Tester1 {
    @Test
    public void test_monthOfDate() {
        assertEquals(1, monthOfDate(2013, 1, 30)); // OK
        assertEquals(1, monthOfDate(2013, 1, 31)); // OK

        // Start of February
        assertEquals(2, monthOfDate(2013, 2, 1));  // FAIL
        assertEquals(2, monthOfDate(2013, 2, 28)); // FAIL
        // to the end of it

        // and after that it is okay also
        assertEquals(3, monthOfDate(2013, 3, 1));  // OK
    }

    public int monthOfDate(int year, int month, int day) {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, month - 1);

        // just a simple get! but seems it is very important
        cal.get(Calendar.MONTH);
        //

        cal.set(Calendar.DAY_OF_MONTH, day);

        return cal.get(Calendar.MONTH) + 1;
    }
}

我想知道为什么会发生这种情况?

1 个答案:

答案 0 :(得分:15)

问题在于,您将于2013年1月30日开始使用日历。

然后您将年份设置为2013年 - 这不是问题。

然后您将月份设置为1(即2月)。你期望在这里发生什么?实际发生的是它会记住它需要将月份设置为1,但重新计算实际时间值。根据{{​​3}}(emphsis mine),您在get的调用中会重新计算时间值

  

set(f,value)将日历字段f更改为值。此外,它设置内部成员变量以指示日历字段f已更改。虽然日历字段f立即更改,但在下一次调用get(),getTime(),getTimeInMillis(),add()或roll()之前,不会重新计算日历的时间值(以毫秒为单位)。因此,对set()的多次调用不会触发多次不必要的计算。作为使用set()更改日历字段的结果,其他日历字段也可能会更改,具体取决于日历字段,日历字段值和日历系统。 此外,在重新计算日历字段后,get(f)不一定会返回通过调用set方法设置的值。详细信息由具体的日历类决定。

当您尝试将“1月30日”更改为“2月30日”并强行进行计算时,实际发生的事情是您最终于3月2日在我的包装盒上结束 - 但它可能会有所不同实施

最好的解决方法是: