0

完全混淆了 java 时间的变化以及为什么有数千篇与此相关的帖子,我以某种方式设法使用 jodaTime 将时间存储在 UTC 中:

Calendar cal = new GregorianCalendar();

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

由于我使用的是休眠(并且不愿意使用适配器让 JodaTime 与版本 4 一起正常工作),我只使用这个 jodaTime 方法将 jdk 时间转换为 utc。这似乎产生了预期的结果,并且本地时间(当前伦敦 GMT+1)通过从本地时间减去 1 转换为 UTC。

到现在为止还挺好。然后,每当我检索特定时区的时间时,我都会得到不正确的偏移量 -2,它应该是 -3,包括 DST。

日历 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 特定时区的时区详细信息

输出:

伦敦当地时间: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

4

1 回答 1

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).

于 2013-10-15T20:54:40.287 回答