Android - junit - 单元测试 - 带时区的 SimpleDateFormat

Android - junit - unit test - SimpleDateFormat with Timezone

我正在使用 Android、JUnit 和 SimpleDateFormat

我喜欢在带时区的 rfc3339 格式的 StringDate 之间做一些转换。

例如:2017-12-31T23:59:59+02:00 但不是 2017-12-31T23:59:59+0200

Android SimpleDateFormat 使用 Z 模式而不是 X 模式(参见下面的 RFC3339_REGEX_1)。

但是在我的JUnit测试(jdk1.8)中,RFC3339_REGEX_1没有给我正确的格式(+02:00),而是+0200。 JUnit 测试在 RFC3339_REGEX_2.

下运行良好

那么我怎样才能做一些在 Android 设备和 JUnit 测试上都运行良好的干净的东西?

public static final String RFC3339_REGEX_1 = "yyyy-MM-dd'T'HH:mm:ssZ"; //android
public static final String RFC3339_REGEX_2 = "yyyy-MM-dd'T'HH:mm:ssXXX"; //java

旧的 classes(DateCalendarSimpleDateFormat)有 lots of problems and design issues, and they're being replaced by the new APIs. And if I'm not wrong, the X pattern doesn't work in all versions (I know that in JDK 6 it wasn't supported, it was introduced only in JDK 7;不确定这会如何影响不同的 Android 版本。

作为替代方案,在 Android 中您可以使用 ThreeTen Backport. To make it work, you'll also need ThreeTenABP (see how to use it ).

如果您仍然需要使用 java.util.Date,那么 API 可以让您的工作变得更轻松。如果您想要像 2017-12-31T23:59:59+02:00 这样的格式,您可以将 java.util.Date 转换为 org.threeten.bp.OffsetDateTime(使用 org.threeten.bp.DateTimeUtils class 来转换值,并使用 org.threeten.bp.ZoneOffset 将偏移量设置为 +02:00):

// assuming that java.util.Date has value equivalent to 2017-12-31T23:59:59+02:00
Date date = ...
// convert to OffsetDateTime (use +02:00 offset)
OffsetDateTime odt = DateTimeUtils.toInstant(date).atOffset(ZoneOffset.of("+02:00"));
System.out.println(odt); // 2017-12-31T23:59:59+02:00

输出将是:

2017-12-31T23:59:59+02:00

注意这是odt.toString()的结果(被System.out.println称为隐式),默认情况下它匹配你想要的格式。但是您也可以通过使用 org.threeten.bp.format.DateTimeFormatter:

强制执行特定格式
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX");
System.out.println(fmt.format(odt));

输出是一样的。唯一的区别是第一个版本(使用 toString())将打印秒的小数部分(如果它们不为零),如果它们为零则将忽略秒,而第二个版本(带有格式化程序)将始终打印以所需的格式(在这种情况下,打印秒而不是秒的小数部分),无论值是否为零。

我相信,在您的情况下,您将需要一个格式化程序,因为您似乎总是需要一种带有秒和没有小数秒的格式。


要将 OffsetDateTime 转换回 Date,您也可以使用 DateTimeUtils

// convert back to java.util.Date
date = DateTimeUtils.toDate(odt.toInstant());

如果不需要使用java.util.Date,可以直接使用OffsetDateTime

// create OffsetDateTime with value = 2017-12-31T23:59:59+02:00
OffsetDateTime odt = OffsetDateTime.of(2017, 12, 31, 23, 59, 59, 0, ZoneOffset.ofHours(2));

还要注意我用的是ZoneOffset.ofHours(2),相当于ZoneOffset.of("+02:00").

您还可以使用 OffsetDateTime.now(ZoneOffset.ofHours(2)) 获取当前日期。


ThreeTen Backport 是新 Java 8 date/time classes 的一个 backport,它有许多不同的日期和时间类型(如上面的 OffsetDateTime)在不同的情况下使用。 Check this tutorial 有关哪种类型最适合您的情况的更多信息 - 本教程涵盖 Java 8,但 ThreeTen Backport 具有相同的 classes 和方法名称,只是包不同:org.threeten.bp 而不是 java.time.