【问题标题】:Converting to UTC considering daylight saving考虑夏令时转换为 UTC
【发布时间】:2014-06-01 13:25:42
【问题描述】:

我有一个日期,例如 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;
    }
}

谁能解释我做错了什么?

【问题讨论】:

  • 将对象转换为字符串然后对其进行解析以将其转换回来并不是一个好习惯。我会使用 joda-time 库进行这样的转换:joda.org/joda-time
  • @Duncan 这是我的错误,我已经对问题进行了更正

标签: java date datetime timezone utc


【解决方案1】:

tl;博士

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

你的输出解释

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

【讨论】:

  • 您是否假设在代码开头的日期值为 Thu April 17 10:03:01 GMT 2014?
  • @DiogoPinheiro 当我运行代码来生成我的示例时,时间是 17-04-2014 11:38:15 BST / 17-04-2014 10:38:15 GMT / 1397731095000ms 自 01 /01/1970.
  • 我怎样才能得到正确的日期?我想要比英国夏令时晚一小时的 UTC。我找不到任何解决方案。谢谢
  • @DiogoPinheiro 正如我所说,Date 代表一个时间点,没有任何时区。如果您想查看特定时区中的日期值(作为字符串),请使用SimpleDateFormat,就像在方法的前四行中一样。
【解决方案2】:

java.util.Date 中没有时区

正如correct answer by Duncan 所说,java.util.Date 没有时区组件。令人困惑的是,它的 toString 方法应用了 JVM 的默认时区。要在其他时区显示,请使用 SimpleDateFormat 应用调整。

更好的是,避免使用臭名昭著的麻烦 java.util.Date、.Calendar 和 SimpleDateFormat。使用 Joda-Time 或 Java 8 中的新 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();

【讨论】:

    猜你喜欢
    • 2012-05-01
    • 1970-01-01
    • 2018-02-04
    • 2021-08-02
    • 1970-01-01
    • 1970-01-01
    • 2015-08-04
    • 2014-04-01
    • 2011-08-14
    相关资源
    最近更新 更多