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.
这里是我的 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.