【问题标题】:DateFormat parse - not return date in UTCDateFormat 解析 - 不返回 UTC 日期
【发布时间】:2017-11-15 12:50:53
【问题描述】:

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

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 IS CORRECT 以 UTC 显示当前日期,但在 parse 之后,dateResult 不正确。为什么?

【问题讨论】:

  • 鉴于 EET 是 UTC+2,对我来说看起来是正确的。您希望看到什么?
  • 日期必须是 UTC。所以我希望看到:Wed Nov 15 12:54:25 UTC 2017
  • Date 没有任何特定时区。 Date#toString() 以您当地的 EET 时区输出。
  • 结果 localTime 和 dateResult 相等。但这是不正确的。他们之间的时间相差 2 小时。
  • 6 小时肯定。

标签: java android datetime utc date-parsing


【解决方案1】:

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

由于您正在为 Android 编写代码,因此第一步是获取 ThreeTenABP,这是一个提供现代 API 的 Android 库(如果您使用的是 Java 8 或 9,则可以跳过这一步,因为将构建现代 API在)。详细信息在this question: How to use ThreeTenABP in Android Project 中进行了描述。现在你可以这样做了:

    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 方法。 Instant 类的对象产生上述格式,始终采用 UTC,正如我理解你想要的那样。在大多数情况下,Instant 类是老式 Date 类的自然替代品。在内部,Instant 保存自纪元以来的秒数和纳秒数,纪元定义为 1970 年 1 月 1 日午夜 0:00 UTC。我鼓励您将其视为无关紧要的实现细节。 Instant 是时间线上的一个点。

出了什么问题?

您要求使用 UTC 日期。这取决于你如何看待它,你可以拥有或不能拥有它。

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

java.time 或 JSR-310

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-20
    • 2011-11-20
    • 1970-01-01
    • 1970-01-01
    • 2016-02-12
    相关资源
    最近更新 更多