Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Month off by one (not due to it being 0-based)

Tags:

java

date

When I set the month on a date representing 1/1/1970, and then immediately get the month back, it's off by one.

import java.util.Date;

@Test
public void monthShouldBeExpectedValue() {
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(new Date(0));

    int expectedMonth = Calendar.JUNE;
    calendar.set(Calendar.MONTH, expectedMonth);
    int actualMonth = calendar.get(Calendar.MONTH);

    assertThat(actualMonth, equalTo(expectedMonth)); // test fails: expected 5 got 6
}

If I change this line

calendar.setTime(new Date(0));

to

calendar.setTime(new Date());  // use 'today' instead of 1/1/1970

then the test passes. Anyone know why?

Edit

The printed version of the dates are:

new Date(0):         Wed Dec 31 19:00:00 EST 1969
date from calendar:  Tue Jul 01 19:00:00 EDT 1969

I'm running an old JDK: 1.6.0_30-b12 (64 bit)

I'm in Eastern Standard Time.

like image 792
Brad Cupit Avatar asked Dec 10 '13 14:12

Brad Cupit


3 Answers

My speculation is that, due to your current timezone, the time is interpreted as December 31, 1969 + a bunch of hours. Setting month to June would therefore result in June 31, 1969 (which doesn't exist; June has 30 days). It therefore rolls over to July.

like image 78
BambooleanLogic Avatar answered Nov 15 '22 18:11

BambooleanLogic


First of all, print calendar to have the exact date.

Then the usual questions:

What's your time zone?

Do you have summer savings time?

Did your time zone change since 1970?

the problem is usually that instead of midnight on the first of the month you get one hour less, i.e. late at night on the last day of the last month.

like image 42
Stroboskop Avatar answered Nov 15 '22 18:11

Stroboskop


The answer by Smallhacker is correct.

Joda-Time

For fun, I tried similar code in Joda-Time 2.3.

Same behavior, which makes sense. If you ask for a DateTime constructed from a milliseconds-from-Epoch of zero, you get start of day of January 1, 1970. But that is the date-time in UTC (no time zone offset).

If you call toString() on that DateTime object using the user's default time zone, of course you see some value other than the Epoch (start of day of January 1, 1970). Unless the user is Icelandic, where they use UTC all year round.

Example Code

DateTime epoch = new DateTime( 0 );
System.out.println( "epoch: " + zero );
System.out.println( "epoch in UTC: " + zero.toDateTime( DateTimeZone.UTC ) );

When run in default time zone of west coast United States…

epoch: 1969-12-31T16:00:00.000-08:00
epoch in UTC: 1970-01-01T00:00:00.000Z

Moral Of The Story

Always specify a time zone; never assume.

Working on date-time values without explicit known time zones is like working on text files without explicit known character encoding. Not smart.

June

To complete the answer to your question but using Joda-Time in a single line of code…

System.out.println( "June after Epoch: " + new DateTime( 0 ).toDateTime( DateTimeZone.UTC ).monthOfYear().setCopy( DateTimeConstants.JUNE ) );

When run…

June after Epoch: 1970-06-01T00:00:00.000Z

This same kind of code is smart enough to handle end-of-month. If the original were January 31, the result would be June 30.

like image 37
Basil Bourque Avatar answered Nov 15 '22 16:11

Basil Bourque