6

I came across a comment in some java code that states that getTime() needs to be called to update the Calendar object. Is this true? I cannot find anything that says that this is necessary.

Here's the code:

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();
Jeremy Cron
  • 2,404
  • 3
  • 25
  • 30
  • also, just to make your code more concise, you should use this version of the constructor: GregorianCalendar(int year, int month, int dayOfMonth) .... none of the other calls are really needed. – Jay Sep 10 '09 at 20:17
  • Please, Check my Answer. – ArtiomLK Nov 11 '16 at 19:58

5 Answers5

12

cal.getTime() does indeed need to be called to re-calculate its internals. It is very strange behavior for the API but the Calendar javadocs state this explicitly:

Getting and Setting Calendar Field Values

The calendar field values can be set by calling the set methods. Any field values set in a Calendar will not be interpreted until it needs to calculate its time value (milliseconds from the Epoch) or values of the calendar fields. Calling the get, getTimeInMillis, getTime, add and roll involves such calculation.

...

Field Manipulation

The calendar fields can be changed using three methods: set(), add(), and roll(). set(f, value) changes calendar field f to value. In addition, it sets an internal member variable to indicate that calendar field f has been changed. Although calendar field f is changed immediately, the calendar's time value in milliseconds is not recomputed until the next call to get(), getTime(), getTimeInMillis(), add(), or roll() is made. Thus, multiple calls to set() do not trigger multiple, unnecessary computations. As a result of changing a calendar field using set(), other calendar fields may also change, depending on the calendar field, the calendar field value, and the calendar system. In addition, get(f) will not necessarily return value set by the call to the set method after the calendar fields have been recomputed. The specifics are determined by the concrete calendar class.

The behavior is unexpected and does not always occur but the following unit tests should exemplify this behavior and always occur.

/**
 * 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());
    }
}
dukethrash
  • 1,449
  • 4
  • 15
  • 25
  • 1
    In short words: If you set the same fields multiple times, for example by setTime(..) and set(Day of week) then you should trigger a recalculate between using getTime() or you will have some strange effect. – Diego Frehner Mar 31 '15 at 14:29
3

@skaffman Answer is NOT CORRECT.

Here is an example which proves what I am saying.

//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());

This is the Log.d output:

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]

If you take time to check it: The calendar at the beginning shows:

time=1478834995641
DAY_OF_MONTH=10  
DAY_OF_YEAR=315

However, when you set it to the first day of the month:

time=?
DAY_OF_MONTH=1  
DAY_OF_YEAR=315

Yes, it changed the first day of the month as we wanted, nevertheless some attributes remain the same. For instance, how it comes we set the calendar to DAY_OF_MONTH=1 but we are still in DAY_OF_YEAR=315.

If we use any of the following functions, it will force the Calendar to update.

Calling the get, getTimeInMillis, getTime, add and roll.

From the Calendar Class in Javadocs Check :Getting and Setting Calendar Field Values

To fix it, we add the following code calendar.getTimeInMillis(); which forces the Calendar to update its attributes.

//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, lets Check Results:

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]

Therefore, @skaffman Answer is not correct, as for your question Calendar.getTime(); indeed is needed if you do not want to get weird values at some point.

ArtiomLK
  • 2,120
  • 20
  • 24
2

You could be hitting Bug ID 4851640

Calling get(...) / getTime() on a Calendar instance makes isSet(...) useless!

Eugene Yokota
  • 94,654
  • 45
  • 215
  • 319
0

No, this is not true.

skaffman
  • 398,947
  • 96
  • 818
  • 769
0

No, it should not be necessary.

Was the Calendar serialized immediate afterwards?

I've been caught by a bug with Calendar serialization in older jvms.

Bug parade bug #4328747

Calling getTime before serialization may be enough to get around the bug, although I don't have a sufficiently old JVM installed for me to confirm that.

Chi
  • 22,624
  • 6
  • 36
  • 37
  • No it wasn't. The workaround for the bug isn't to call getTime() but rather get/setGregorianChange(). I was thinking that this may have been a bug a long time ago (this is older code I'm looking at) but it appears as if that isn't the case. – Jeremy Cron Sep 10 '09 at 18:57
  • There were actually several different workarounds that worked, getGregorianChange was one of them, but getTime may have been another of them. anyways, its irrelevant if was wasn't serialized anyways – Chi Sep 10 '09 at 19:01