考虑夏令时转换为UTC

时间:2014-04-17 10:13:58

标签: java date datetime timezone utc

我有一个约会日期,例如 Thu April 17 09:03:01 GMT 2014 :时区:

sun.util.calendar.ZoneInfo[id="Europe/London",offset=0,dstSavings=3600000,useDaylight=true,transitions=242,lastRule=java.util.SimpleTimeZone[id=Europe/London,offset=0,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]]

每次尝试转换为UTC时,它都会返回 Thu April 17 10:03:01 GMT 2014

这没有意义,因为相应的UTC时间实际上是 Thu April 17 08:03:01 GMT 2014 ,因为我的时区时间因夏令时而增加了1小时。

我用来转换的代码是:

//timeZone - id="Europe/London"
public static Date timeZoneConvertDate(Date date, TimeZone timeZone) {
        SimpleDateFormat sdf = new SimpleDateFormat();
        sdf.setTimeZone(timeZone);
        sdf.applyPattern("dd-MM-yyyy HH:mm:ss");
        String newDate = sdf.format(date);
        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
        try {
            Date nd = sdf.parse(newDate);
            return nd;
        } catch (ParseException e) {
            return null;
    }
}

有人可以解释我做错了吗?

2 个答案:

答案 0 :(得分:1)

TL;博士

Date没有与之关联的时区,因此您无法创建调整日期对象时区的方法。如果您想保留TZ信息,或者最好查看Joda-Time,则需要使用Calendar个对象。

您的输出说明

Date值没有时区信息;它只是自纪元以来的毫秒数。考虑到这一点,让我们看看你在做什么:

SimpleDateFormat sdf = new SimpleDateFormat();
sdf.setTimeZone(timeZone);
sdf.applyPattern("dd-MM-yyyy HH:mm:ss");
String newDate = sdf.format(date);

这部分代码会创建一个格式化程序,用于在伦敦时区打印日期。因此,您在撰写本文时得到的结果大约是:17-04-2014 11:38:15(假设您刚刚创建了日期对象)。

sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
try {
  Date nd = sdf.parse(newDate);
  return nd;
} catch (ParseException e) {
   return null;
}

在这里,您告诉日期解析器读取日期,就像它是UTC日期一样。它使用该信息来了解自纪元已经过去多少毫秒。您获取的日期对象仍然没有与之关联的时区

UTC比英国夏令时晚一个小时,所以它会创建一个日期对象,在BST时区打印时提前一小时出现。因此,当我打印nd时,我得到:Thu Apr 17 12:38:15 BST 2014

答案 1 :(得分:1)

java.util.Date中没有时区

由于correct answer by Duncan表示java.util.Date没有时区组件。令人困惑的是它的toString方法应用了JVM的默认时区。要在另一个时区显示,请使用SimpleDateFormat应用调整。

更好的是,避免使用臭名昭着的java.util.Date,.Calendar和SimpleDateFormat。在Java 8中使用Joda-Time或新的java.time包。

约达时间

在Joda-Time中,DateTime对象确实包含指定的时区。如果未指定时区,则会分配JVM的默认时区。

DateTimeZone timeZone = DateTimeZone.forID( "Europe/London" );
DateTime dateTime = new DateTime( 2014, 4, 17, 9, 3, 1, timeZone );
DateTime dateTimeUtc = dateTime.withZone( DateTimeZone.UTC );
DateTime dateTimeIndia = dateTime.withZone( DateTimeZone.forID( "Asia/Kolkata" ) );

跑步时......

dateTime: 2014-04-17T09:03:01.000+01:00
dateTimeUtc: 2014-04-17T08:03:01.000Z
dateTimeIndia: 2014-04-17T13:33:01.000+05:30 (note the half-hour difference, +05:30)

您可以轻松地来回转换为java.util.Date。

DateTime dateTime = new DateTime( myJUDate, timeZone );

...和...

Java.util.Date date = dateTime.toDate();