正在调用Java';更新对象需要s Calendar.getTime()吗?

正在调用Java';更新对象需要s Calendar.getTime()吗?,java,calendar,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 c

我在一些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();

不,这不是真的。

不,应该没有必要

之后日历是否立即序列化

我在较旧的JVM中遇到了一个日历序列化错误

在序列化之前调用getTime可能足以绕过这个bug,尽管我没有安装足够旧的JVM来确认这一点。

您可能会遇到问题

在日历实例上调用get(…)/getTime()会使isSet(…)毫无用处

确实需要调用
cal.getTime()
来重新计算其内部结构。API的行为非常奇怪,但该状态明确表示:

获取和设置日历字段值

可以通过调用set方法来设置日历字段值。任何 日历中设置的字段值在需要时才会被解释 计算其时间值(从历元算起的毫秒)或 日历字段。调用get,getTimeInMillis,getTime,add 而roll就涉及到这样的计算

字段操作

可以使用以下三种方法更改日历字段:set()、add(), 然后滚动()。set(f,value)将日历字段f更改为value。在里面 此外,它还设置了一个内部成员变量,以指示 日历字段f已更改。虽然日历字段f是 如果立即更改,则日历的时间值(以毫秒为单位)不可用 重新计算,直到下一次调用get()、getTime()、getTimeInMillis(), 添加(),或进行滚动()。因此,对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());
    }
}

@斯卡夫曼的回答不正确

这里有一个例子可以证明我所说的

//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\u OF\u MONTH=1
,但仍处于
DAY\u OF\u YEAR=315

如果我们使用以下任何函数,它将强制更新日历

调用get、getTimeInMillis、getTime、add和roll

从Javadocs中的Calendar类检查:

为了修复它,我们添加了以下代码
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()

它曾经出现在java的某个早期版本中吗?不,从来没有。现有的行为永远不会以这种方式改变。如果这是真的,它将是设计糟糕的API的一个很好的例子。Getter方法应该是只读的(这是因为我错过了C++中的const修饰符)。@abahgat-我同意,这就是我质疑它的原因。开发人员也没有将结果分配给任何东西。他们只是使用它,好像它没有返回任何东西一样。@abahgat:
java.util.Calendar
是一个设计非常糟糕的APINo,事实并非如此。该错误的解决方法不是调用getTime(),而是get/setGregorianChange()。我认为这可能是很久以前的一个bug(这是我正在查看的较旧的代码),但似乎不是这样。实际上有几种不同的解决方法,getGregorianChange是其中之一,但getTime可能是另一种。不管怎么说,如果没有序列化,它就无关紧要了anyways@eed3si9n-很好的发现-我不认为我们正在使用isSet,但我会再看一遍。另外,为了使代码更简洁,您应该使用这个版本的构造函数:GregorianCalendar(int year,int month,int dayOfMonth)。。。。其他调用都不需要。请检查我的答案。简言之:如果多次设置相同的字段,例如通过setTime(..)和set(星期几),则应在使用getTime()之间触发重新计算,否则会产生一些奇怪的效果。