DateFormat 解析 - 不是 return UTC 日期

DateFormat parse - not return date in UTC

这里是我的 java 代码,它试图在 Android 设备上以 UTC 格式获取当前日期:

public static Date getCurrentDateUTC() {
    try {
        TimeZone timeZoneUTC = TimeZone.getTimeZone("UTC");
        Date localTime = new Date();
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss Z");
        dateFormat.setTimeZone(timeZoneUTC);
        String dateUTCAsString = dateFormat.format(localTime);
        Debug.d(TAG, "getCurrentDateUTC: dateUTCAsString = " + dateUTCAsString);
        Date dateResult = dateFormat.parse(dateUTCAsString);
        Debug.d(TAG, "getCurrentDateUTC: dateResult = " + dateResult);
        return dateResult;
    } catch (ParseException e) {
        Debug.e(TAG, "getCurrentDateUTC: ", e);
        return null;
    }
}

结果:

dateUTCAsString = 2017-11-15T12:54:25 +0000
dateResult = Wed Nov 15 14:54:25 EET 2017

如您所见,dateUTCAsString 以 UTC 显示当前日期是正确的,但在 parse 之后 dateResult 不是正确的。为什么?

不好意思提一下,我怀疑你的代码没有问题,只是乱码。如果您认为旧 Date class 的行为令人困惑,请允许我成为第一个同意您的人。解决此问题的好方法是停止使用 Date 并开始使用现代 Java 日期和时间 API。

由于您正在为 Android 编码,因此第一步是获取 ThreeTenABP,这是 Android 的库,它提供了现代 API(如果您使用的是 Java 8 或 9,你可以跳过这一步,因为现代的 API 是内置的)。 中描述了详细信息。现在您可以:

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss Z");
    String dateUTCAsString = "2017-11-15T12:54:25 +0000";
    Instant dateResult = OffsetDateTime.parse(dateUTCAsString, formatter).toInstant();
    System.out.println(dateResult);

在我的电脑上刚刚打印出来:

2017-11-15T12:54:25Z

最后的Z表示祖鲁时区或UTC。

如您所知,System.out.println(dateResult) 隐式调用了 dateResult 对象的 toString 方法。 class Instant 的对象产生上面的格式,总是在 UTC 中,正如我所理解的你想要的。在大多数情况下,Instant class 是老式 Date class 的自然替代品。 Instant 在内部保存自纪元以来的秒数和纳秒数,纪元定义为 1970 年 1 月 1 日 0:00 午夜 UTC。我鼓励您将此视为无关紧要的实施细节。 Instant 是时间线上的一个点。

哪里出了问题?

您要求的日期为 UTC。取决于你如何看待它,你可以或不可以。

  • 一方面,Date 被实现为自纪元以来的秒数和毫秒数,因此如果您使用纪元的上述定义,您可能会说它总是 以 UTC 表示。
  • 另一方面,您不必担心实施细节。从概念上讲,Date(如 Instant)是时间线上的一个点,没有也不可能有时区或偏移量;它不能在 UTC 中。更令人困惑的是,当您执行 "getCurrentDateUTC: dateResult = " + dateResult 时,会隐式调用 dateResult.toString()。此方法获取 JVM 的时区设置并将日期时间转换为该时区并将其用于生成的字符串(无需修改 Date 对象)。这就是为什么无论您尝试打印哪个 Date,您都会在您的计算机或设备上看到 EET 时间。

java.time 或 JSR-310

现代日期和时间 API 被称为 java.time 或 JSR-310。学习使用它的一个很好的来源是 the Oracle tutorial.