Brad Cupit
Brad Cupit

Reputation: 6580

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

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.

Upvotes: 11

Views: 905

Answers (3)

Basil Bourque
Basil Bourque

Reputation: 338785

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.

Upvotes: 2

BambooleanLogic
BambooleanLogic

Reputation: 8161

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.

Upvotes: 13

Stroboskop
Stroboskop

Reputation: 4356

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.

Upvotes: 4

Related Questions