DateFormat解析 - 不以UTC格式返回日期

时间:2017-11-15 12:50:54

标签: java android datetime utc date-parsing

这是我试图在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 不正确。为什么呢?

1 个答案:

答案 0 :(得分: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)隐式调用toString对象的dateResult方法。类Instant的对象产生上述格式,总是以UTC为单位,正如我所理解的那样。对于大多数用途,Instant类是旧式Date类的自然替代品。在内部,Instant保存自纪元以来的秒数和纳秒数,该纪元定义为1970年1月1日UTC午夜0点。我鼓励您将此视为无关的实施细节。 Instant是时间线上的一个点。

出了什么问题?

您要求提供UTC日期。根据您的观察方式,您可以或不可以。

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

java.time或JSR-310

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