0

Being entirely confused of what's going in with java time and why there are thousands of posts related to this I somehow managed to store time in UTC using jodaTime:

Calendar cal = new GregorianCalendar();

cal.setTimeInMillis(DateTimeZone.getDefault().convertLocalToUTC(
                            cal.getTimeInMillis(), false));

Since I am using hibernate(and not willing to use adapters for JodaTime to work correctly with version 4) I only use this jodaTime method to convert jdk time to utc. This seems to produce expected result and the local time(current london GMT+1) gets converted to UTC via subtracting 1 from this local time.

So far so good. Then whenever I retrieve my time for specific timezone I get incorrect offset of -2 where it should be -3 including DST.

Calendar cal = new GregorianCalendar();

          System.out.println("Local London Hours: "+cal.get(Calendar.HOUR_OF_DAY));
          System.out.println("Local London Milliseconds: "+cal.getTimeInMillis());

          cal.setTimeInMillis(DateTimeZone.getDefault().convertLocalToUTC(
                  cal.getTimeInMillis(), false));

          System.out.println("UTC Hours: "+cal.get(Calendar.HOUR_OF_DAY));
          System.out.println("UTC Milliseconds: "+cal.getTimeInMillis());

          // Time for specific time zone
          cal.setTimeZone(TimeZone.getTimeZone("Europe/Vilnius"));


          System.out.println("Vilnius Hours: "+cal.get(Calendar.HOUR_OF_DAY));
          System.out.println("Vilnius Milliseconds: "+cal.getTimeInMillis());

          // is this time in DST? - Yes
          System.out.println("Vilnius time is in DST: "+TimeZone.getTimeZone("Europe/Vilnius").inDaylightTime(cal.getTime()));

http://www.timeanddate.com/worldclock/city.html?n=660 Time zone details for specific timezone

Output:

Local London Hours: 21

Local London Milliseconds: 1381869901339

UTC Hours: 20

UTC Milliseconds: 1381866301339

Vilnius Hours: 22 // this should be 23 (according to link)

Vilnius Milliseconds: 1381866301339

Vilnius time is in DST: true // no, it is not since hours value is not 23

Aubergine
  • 5,862
  • 19
  • 66
  • 110

1 Answers1

1

Use

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("Europe/London");

to get London time.

You should be able to change it to UTC with:

cal.setTimeZone(TimeZone.getTimeZone("UTC"));

But, there is a funny thing about the Calendar class. Before you change the time zone and afterwards, it works best if you get some value from it. So add a line like,

cal.get(Calendar.HOUR_OF_DAY);

This causes the Calendar object to readjust all its internal fields.

The problem is that it stores the time in milliseconds and it stores the hour and day and minute and all that in other fields. If you set the hour, it doesn't update the millisecond time until you read some field. That's in case you are going to set the date and the hour and everything so it doesn't have to recalculate every time, just once you get them all changed.

Similarly, if you change the millisecond time or the timezone, it doesn't recalculate the hour and day and such until you read them.

(Note that this will totally confuse you if you are using a debugger because the debugger will typically call one of the get()s to display values in the debug console. That will fix the Calendar object and you won't have the problem when single-stepping. Can you tell I've been there?)

So ... it can get confused and the magic line above makes it work if you put it in enough in the right place. And it never hurts.

NOTE

If you store the calendar as a TIMESTAMP in a database using JDBC, it will store the millisecond time (or we can think of it that way).

Then, when JDBC reads the millisecond time, creates a Calendar object and returns it to you. The created Calendar has the default TimeZone in it.

Deal with this just as you did with converting the London time to UTC.

cal.get(Calendar.HOUR_OF_DAY); // funky Calendar magic to make sure it works
cal.setTimeZone(TimeZone.getTimeZone("UTC"));

All this does is change the stored TimeZone so that when the next code like get(Calendar.HOUR_OF_DAY) executes, it converts the stored millisecond value to the correct timezone's hour of the day (i.e. UTC).

Lee Meador
  • 12,829
  • 2
  • 36
  • 42
  • I think it is equivalent to new GregorianCalendar() since server is in london? – Aubergine Oct 15 '13 at 20:58
  • It should be but using `Calendar` is akin to black magic. You have to get the incantations just right for it to work. – Lee Meador Oct 15 '13 at 21:03
  • I follow you as you update your answer, I think this line solves my problem cal.setTimeZone(TimeZone.getTimeZone("UTC")); I will check if it saves the value correctly into db (as jodaTime method seems to do that well but break everything else). Accepting soon. – Aubergine Oct 15 '13 at 21:04
  • Well your answer solves one problem but creates another. My date is no longer saved in UTC +0 (as it was with jodaTime method) inside database but now in UTC +1 or London local time, which is wrong? I am confused :-) – Aubergine Oct 15 '13 at 21:20
  • Does the saved value include the time zone? – Lee Meador Oct 15 '13 at 23:03
  • You might want to read this: http://stackoverflow.com/questions/508019/jpa-hibernate-store-date-in-utc-time-zone as its a common problem. – Lee Meador Oct 15 '13 at 23:08
  • Yeah found it, currently looking at. It seems though that it does not really affect anything apart from the way it looks it db. Converting back to UTC from db works as expected. Thanks for your time ! – Aubergine Oct 15 '13 at 23:18
  • The problem seems to be that the JDBC code creates a `Calendar` object and that object has the default time zone. You should be able to take the returned `Calendar` and do a `get` and a `setTimeZone` to change it to UTC. – Lee Meador Oct 15 '13 at 23:21