tags:

views:

2919

answers:

6

Program followed by output. Someone please explain to me why 10,000,000 milliseconds from Jan 1, 1970 is November 31, 1969. Well, someone please explain what's wrong with my assumption that the first test should produce a time 10,000,000 milliseconds from Jan 1, 1970. Numbers smaller than 10,000,000 produce the same result.

public static void main(String[] args) {

 String x = "10000000";
 long l = new Long(x).longValue();
 System.out.println("Long value: " + l);

 Calendar c = new GregorianCalendar();
 c.setTimeInMillis(l);
 System.out.println("Calendar time in Millis: " + c.getTimeInMillis());

 String origDate = c.get(Calendar.YEAR) + "-" + c.get(Calendar.MONTH) + "-" + c.get(Calendar.DAY_OF_MONTH);  
 System.out.println("Date in YYYY-MM-DD format: " + origDate);

 x = "1000000000000";
 l = new Long(x).longValue();
 System.out.println("\nLong value: " + l);

 c.setTimeInMillis(l);
 System.out.println("Calendar time in Millis: " + c.getTimeInMillis());

 origDate = c.get(Calendar.YEAR) + "-" + c.get(Calendar.MONTH) + "-" + c.get(Calendar.DAY_OF_MONTH);  
 System.out.println("Date in YYYY-MM-DD format: " + origDate);
}

Long value: 10000000

Calendar time in Millis: 10000000

Date in YYYY-MM-DD format: 1969-11-31

Long value: 1000000000000

Calendar time in Millis: 1000000000000

Date in YYYY-MM-DD format: 2001-8-8

A: 

You can figure out yourself if you change your first c.setTimeInMillis(l); in c.clear();

Davide
+6  A: 

The dates you print from Calendar are local to your timezone, whereas the epoch is defined to be midnight of 1970-01-01 in UTC. So if you live in a timezone west of UTC, then your date will show up as 1969-12-31, even though (in UTC) it's still 1970-01-01.

Chris Jester-Young
Thanks! I thought I was going crazy.
Nathan Spears
+5  A: 

First, c.get(Calendar.MONTH) returns 0 for Jan, 1 for Feb, etc.

Second, use DateFormat to output dates.

Third, your problems are a great example of how awkward Java's Date API is. Use Joda Time API if you can. It will make your life somewhat easier.

Here's a better example of your code, which indicates the timezone:

public static void main(String[] args) {

    final DateFormat dateFormat = SimpleDateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL);

    long l = 10000000L;
    System.out.println("Long value: " + l);
    Calendar c = new GregorianCalendar();
    c.setTimeInMillis(l);
    System.out.println("Date: " + dateFormat.format(c.getTime()));

    l = 1000000000000L;
    System.out.println("\nLong value: " + l);
    c.setTimeInMillis(l);
    System.out.println("Date: " + dateFormat.format(c.getTime()));
}
Steve McLeod
Very helpful; you answered my question a bit indirectly. The time zone thing was causing me the most confusion. The improved code is greatly appreciated.
Nathan Spears
+4  A: 

Calendar#setTimeInMillis() sets the calendar's time to the number of milliseconds after Jan 1, 1970 GMT.

Calendar#get() returns the requested field adjusted for the calendar's timezone which, by default, is your machine's local timezone.

This should work as you expect if you specify "GMT" timezone when you construct the calendar:

Calendar c = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
Mike
Thanks for the code example.
Nathan Spears
+1  A: 

Your timezone is most likely lagging behind GMT (e.g., GMT-5), therefore 10,000,000ms from epoch is December 31 1969 in your timezone, but since months are zero-based in java.util.Calendar your Calendar->text conversion is flawed and you get 1969-11-31 instead of the expected 1969-12-31.

Alexander
+1  A: 

Sadly, java.util.Date and java.util.Calendar were poorly designed leading to this sort of confusion.

Julien Chastang