Android - junit - 单元测试 - 带时区的 SimpleDateFormat
Android - junit - unit test - SimpleDateFormat with Timezone
我正在使用 Android、JUnit 和 SimpleDateFormat
。
我喜欢在带时区的 rfc3339 格式的 String
和 Date
之间做一些转换。
例如: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(Date
、Calendar
和 SimpleDateFormat
)有 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
.
我正在使用 Android、JUnit 和 SimpleDateFormat
。
我喜欢在带时区的 rfc3339 格式的 String
和 Date
之间做一些转换。
例如: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(Date
、Calendar
和 SimpleDateFormat
)有 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
.