调用Java的Calendar.getTime()是否需要更新对象?

时间:2009-09-10 18:44:30

标签: java calendar

我在一些java代码中发现了一条注释,指出需要调用getTime()来更新Calendar对象。这是真的?我找不到任何说这是必要的东西。

以下是代码:

Calendar cal = new GregorianCalendar();
cal.setFirstDayOfWeek(Calendar.SUNDAY);
cal.set(2009, 9 - 1, 10, 2, 30);
// Get Time needs to be called to update the Calendar object
cal.getTime();

5 个答案:

答案 0 :(得分:9)

确实需要调用

cal.getTime()来重新计算其内部结构。这是一种非常奇怪的API行为,但Calendar javadocs明确说明了这一点:

  

获取和设置日历字段值

     

可以通过调用set方法来设置日历字段值。任何   在需要之前,不会解释在日历中设置的字段值   计算其时间值(距离纪元的毫秒数)或值   日历字段。调用get,getTimeInMillis,getTime,添加   和滚动涉及这样的计算。

...

  

Field Manipulation

     

可以使用三种方法更改日历字段:set(),add(),   和roll()。 set(f,value)将日历字段f更改为值。在   另外,它设置一个内部成员变量来表示   日历字段f已更改。虽然日历字段f是   立即更改,日历的时间值(以毫秒为单位)不是   重新计算,直到下一次调用get(),getTime(),getTimeInMillis(),   制作了add()或roll()。因此,不会触发多次调用set()   多次,不必要的计算。由于更改日历   使用set()的字段,其他日历字段也可能会更改,具体取决于   日历字段,日历字段值和日历系统。   另外,get(f)不一定返回调用设置的值   重新计算日历字段后的set方法。该   细节由具体的日历类确定。

行为是意外的,并不总是发生,但以下单元测试应该举例说明这种行为并且总是发生。

/**
 * Fails the assertion due to missing getTime()
 * @throws ParseException 
 */
public class DateTest {

    @Test
    public void testNoGetTime() throws ParseException {

        DateFormat df = new SimpleDateFormat("MM/dd/yyyy");
        Date testDate = df.parse("04/15/2013");
        Calendar testCal = Calendar.getInstance();
        testCal.setTime(testDate);
        Date expectedDate = df.parse("04/04/2013");
        Date actualDate = null;

        testCal.set(Calendar.DAY_OF_MONTH, testCal.getMinimum(Calendar.DAY_OF_MONTH));
        //testCal.getTime();
        testCal.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
        testCal.add(Calendar.DAY_OF_MONTH, -1);
        actualDate = testCal.getTime();
        assertEquals("Dates should be equal", expectedDate.toString(), actualDate.toString());
    }

    @Test
    public void testWithGetTime() throws ParseException {

        DateFormat df = new SimpleDateFormat("MM/dd/yyyy");
        Date testDate = df.parse("04/15/2013");
        Calendar testCal = Calendar.getInstance();
        testCal.setTime(testDate);
        Date expectedDate = df.parse("04/04/2013");
        Date actualDate = null;

        testCal.set(Calendar.DAY_OF_MONTH, testCal.getMinimum(Calendar.DAY_OF_MONTH));
        testCal.getTime();
        testCal.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
        testCal.add(Calendar.DAY_OF_MONTH, -1);
        actualDate = testCal.getTime();
        assertEquals("Dates should be equal", expectedDate.toString(), actualDate.toString());
    }
}

答案 1 :(得分:2)

你可能正在点击Bug ID 4851640

  

在Calendar实例上调用get(...)/ getTime()会使isSet(...)无效!

答案 2 :(得分:2)

@skaffman答案 NOT CORRECT

这是一个证明我在说什么的例子。

//Create an Calendar object set to todays date & time
Calendar calendar = Calendar.getInstance();
Log.d(Tag, "Now : "+ calendar.toString());

//Set the Calendar to the first day of Month
calendar.set(Calendar.DAY_OF_MONTH,1);
Log.d(Tag, "Calendar.DAY_OF_MONTH,1: "+ calendar.toString());

这是Log.d输出:

Now : java.util.GregorianCalendar[time=1478834995641,areFieldsSet=true,lenient=true,zone=America/Chicago,firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2016,MONTH=10,WEEK_OF_YEAR=46,WEEK_OF_MONTH=2,DAY_OF_MONTH=10,DAY_OF_YEAR=315,DAY_OF_WEEK=5,DAY_OF_WEEK_IN_MONTH=2,AM_PM=1,HOUR=9,HOUR_OF_DAY=21,MINUTE=29,SECOND=55,MILLISECOND=641,ZONE_OFFSET=-21600000,DST_OFFSET=0] Calendar.DAY_OF_MONTH,1: 
Calendar.DAY_OF_MONTH,1: java.util.GregorianCalendar[time=?,areFieldsSet=false,lenient=true,zone=America/Chicago,firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2016,MONTH=10,WEEK_OF_YEAR=46,WEEK_OF_MONTH=2,DAY_OF_MONTH=1,DAY_OF_YEAR=315,DAY_OF_WEEK=5,DAY_OF_WEEK_IN_MONTH=2,AM_PM=1,HOUR=9,HOUR_OF_DAY=21,MINUTE=29,SECOND=55,MILLISECOND=641,ZONE_OFFSET=-21600000,DST_OFFSET=0]

如果你花时间检查它: 开头的日历显示:

time=1478834995641
DAY_OF_MONTH=10  
DAY_OF_YEAR=315

但是,当您将其设置为该月的第一天时:

time=?
DAY_OF_MONTH=1  
DAY_OF_YEAR=315

是的,它改变了我们想要的月份的第一天,但​​有些属性保持不变。例如,我们如何将日历设置为DAY_OF_MONTH=1,但我们仍然在DAY_OF_YEAR=315

如果我们使用以下任何功能,它将强制更新日历。

  

调用get,getTimeInMillis,getTime,add和roll。

来自Javadocs中的日历类检查:Getting and Setting Calendar Field Values

要解决此问题,我们添加以下代码calendar.getTimeInMillis();,强制日历更新其属性。

//Create an Calendar object set to todays date & time
Calendar calendar = Calendar.getInstance();
Log.d(Tag, "Now : "+ calendar.toString());

//Set the Calendar to the first day of Month
calendar.set(Calendar.DAY_OF_MONTH,1);
//UPDATE BY CALLING getTimeInMillis() or any of the previously mentioned functions
calendar.getTimeInMillis();
Log.d(Tag, "Calendar.DAY_OF_MONTH,1: "+ calendar.toString());

现在,让我们检查结果:

Now : java.util.GregorianCalendar[time=1478836452183,areFieldsSet=true,lenient=true,zone=America/Chicago,firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2016,MONTH=10,WEEK_OF_YEAR=46,WEEK_OF_MONTH=2,DAY_OF_MONTH=10,DAY_OF_YEAR=315,DAY_OF_WEEK=5,DAY_OF_WEEK_IN_MONTH=2,AM_PM=1,HOUR=9,HOUR_OF_DAY=21,MINUTE=54,SECOND=12,MILLISECOND=183,ZONE_OFFSET=-21600000,DST_OFFSET=0]
Calendar.DAY_OF_MONTH,1: java.util.GregorianCalendar[time=1478055252183,areFieldsSet=true,lenient=true,zone=America/Chicago,firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2016,MONTH=10,WEEK_OF_YEAR=45,WEEK_OF_MONTH=1,DAY_OF_MONTH=1,DAY_OF_YEAR=306,DAY_OF_WEEK=3,DAY_OF_WEEK_IN_MONTH=1,AM_PM=1,HOUR=9,HOUR_OF_DAY=21,MINUTE=54,SECOND=12,MILLISECOND=183,ZONE_OFFSET=-21600000,DST_OFFSET=3600000]

因此,@skaffman答案是不正确的,至于你的问题Calendar.getTime();确实需要,如果你不想在某个时候得到奇怪的值。

答案 3 :(得分:0)

不,这不是真的。

答案 4 :(得分:0)

不,没有必要。

之后日历是否立即序列化?

我遇到了旧版jvms中日历序列化的错误。

Bug parade bug #4328747

在序列化之前调用getTime可能足以解决这个问题,虽然我没有安装足够旧的JVM来确认这一点。