yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'转换为日期格式
yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z' convert to date format
我收到来自 API 的日期,格式如下:
yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'
并以这种方式转换它:
String rawDate = "2017-05-11T15:46:48.2226756Z";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'", Locale.getDefault());
Date date = simpleDateFormat.parse(rawDate);
System.out.println(date); //Thu May 11 16:23:54 PDT 2017
但是日期输出是这样的:
Thu May 11 16:23:54 PDT 2017
输出应该是:
Thu May 11 15:46:48 PDT 2017
如何正确转换原始日期?
问题是'S'代表毫秒。因此,在您的情况下,您告诉它时间是 15 小时 46 分 48 秒 2226756 毫秒 。如果你在 15:46:48 上加上 2226756 毫秒,即 2226 秒和 756 毫秒,你确实得到 16:23:54.
最简单的解决方案可能是只在字符串中找到句点,然后将字符串截断三处,即将其转换为:
2017-05-11T15:46:48.222
您可以使用以下行实现此目的:
rawDate = rawDate.substring(0, rawDate.indexOf('.') + 4);
然后用
解析
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.getDefault());
请注意,这没有正确舍入微秒。例如,在您的情况下,222.6756ms 应该四舍五入为 223ms,而不是 222ms。如果这很重要,您可以通过检查第一个丢弃的数字以查看它是否为 5 或更高并向 date
.
添加毫秒来手动执行此操作
更新(回复:Basil Bourque):
如果您想真正遵守时间字符串中的时区标识符(表示 UTC,如下面 Ole V.V 所述),您只需将 'UTC' 添加到字符串的末尾并在旧版本 Java 中使用该时区对其进行解析,而不使用任何其他库:
rawDate = rawDate.substring(0, rawDate.indexOf('.') + 4) + "UTC";
SimpleDateFormat sDF = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSz",
Locale.getDefault());
Date date = sDF.parse(rawDate);
您可以直接使用下面的解析。
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
SimpleDateFormat
无法处理三秒(毫秒)以外的任何其他小数位数,因此无法让它正确解析您的字符串。此外,较新的 Java 日期和时间 classes 通常对程序员更加友好和方便。它们具有纳秒精度(秒上有 9 位小数)。所以我建议您考虑继续使用它们。
如前所述,Z表示祖鲁时区,也称为UTC。所以 2017-05-11T15:46:48.2226756Z
表示 15:46:48 UTC,等于 8:46:48 太平洋夏令时。你的格式暂时是ISO 8601格式,Instant
class理解为默认格式,所以解析很容易:
Instant instant = Instant.parse(rawDate);
结果是
2017-05-11T15:46:48.222675600Z
唯一需要注意的是添加的两个零。 toString
方法以三个为一组打印小数,足够的组来呈现完整的精度。所以 7 位小数它打印 9.
获取太平洋时区的日期:
ZonedDateTime dateTime = instant.atZone(ZoneId.of("America/Los_Angeles"));
结果和我预测的一样:
2017-05-11T08:46:48.222675600-07:00[America/Los_Angeles]
现在假设您的原始日期时间字符串是从某个人那里得到的,但他误解了您的意思,实际上是 2017 年 5 月 11 日星期四 15:46:48 PDT(这不是历史上第一次)。然后你需要把它转换成那个。同样,虽然这对于老式的 classes 来说很麻烦,但对于较新的 es 来说却很顺利:
ZonedDateTime dateTime = instant.atOffset(ZoneOffset.UTC)
.atZoneSimilarLocal(ZoneId.of("America/Los_Angeles"));
结果就是你要的结果(除了我也给你所有小数):
2017-05-11T15:46:48.222675600-07:00[America/Los_Angeles]
对于 Android,您从 ThreeTenABP 库中获取更新的日期和时间 classes。
链接
- Oracle 教程:Trail: Date Time
- 日期和时间 classes Android: ThreeTenABP
- 问题
我收到来自 API 的日期,格式如下:
yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'
并以这种方式转换它:
String rawDate = "2017-05-11T15:46:48.2226756Z";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'", Locale.getDefault());
Date date = simpleDateFormat.parse(rawDate);
System.out.println(date); //Thu May 11 16:23:54 PDT 2017
但是日期输出是这样的:
Thu May 11 16:23:54 PDT 2017
输出应该是:
Thu May 11 15:46:48 PDT 2017
如何正确转换原始日期?
问题是'S'代表毫秒。因此,在您的情况下,您告诉它时间是 15 小时 46 分 48 秒 2226756 毫秒 。如果你在 15:46:48 上加上 2226756 毫秒,即 2226 秒和 756 毫秒,你确实得到 16:23:54.
最简单的解决方案可能是只在字符串中找到句点,然后将字符串截断三处,即将其转换为:
2017-05-11T15:46:48.222
您可以使用以下行实现此目的:
rawDate = rawDate.substring(0, rawDate.indexOf('.') + 4);
然后用
解析SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.getDefault());
请注意,这没有正确舍入微秒。例如,在您的情况下,222.6756ms 应该四舍五入为 223ms,而不是 222ms。如果这很重要,您可以通过检查第一个丢弃的数字以查看它是否为 5 或更高并向 date
.
更新(回复:Basil Bourque):
如果您想真正遵守时间字符串中的时区标识符(表示 UTC,如下面 Ole V.V 所述),您只需将 'UTC' 添加到字符串的末尾并在旧版本 Java 中使用该时区对其进行解析,而不使用任何其他库:
rawDate = rawDate.substring(0, rawDate.indexOf('.') + 4) + "UTC";
SimpleDateFormat sDF = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSz",
Locale.getDefault());
Date date = sDF.parse(rawDate);
您可以直接使用下面的解析。
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
SimpleDateFormat
无法处理三秒(毫秒)以外的任何其他小数位数,因此无法让它正确解析您的字符串。此外,较新的 Java 日期和时间 classes 通常对程序员更加友好和方便。它们具有纳秒精度(秒上有 9 位小数)。所以我建议您考虑继续使用它们。
如前所述,Z表示祖鲁时区,也称为UTC。所以 2017-05-11T15:46:48.2226756Z
表示 15:46:48 UTC,等于 8:46:48 太平洋夏令时。你的格式暂时是ISO 8601格式,Instant
class理解为默认格式,所以解析很容易:
Instant instant = Instant.parse(rawDate);
结果是
2017-05-11T15:46:48.222675600Z
唯一需要注意的是添加的两个零。 toString
方法以三个为一组打印小数,足够的组来呈现完整的精度。所以 7 位小数它打印 9.
获取太平洋时区的日期:
ZonedDateTime dateTime = instant.atZone(ZoneId.of("America/Los_Angeles"));
结果和我预测的一样:
2017-05-11T08:46:48.222675600-07:00[America/Los_Angeles]
现在假设您的原始日期时间字符串是从某个人那里得到的,但他误解了您的意思,实际上是 2017 年 5 月 11 日星期四 15:46:48 PDT(这不是历史上第一次)。然后你需要把它转换成那个。同样,虽然这对于老式的 classes 来说很麻烦,但对于较新的 es 来说却很顺利:
ZonedDateTime dateTime = instant.atOffset(ZoneOffset.UTC)
.atZoneSimilarLocal(ZoneId.of("America/Los_Angeles"));
结果就是你要的结果(除了我也给你所有小数):
2017-05-11T15:46:48.222675600-07:00[America/Los_Angeles]
对于 Android,您从 ThreeTenABP 库中获取更新的日期和时间 classes。
链接
- Oracle 教程:Trail: Date Time
- 日期和时间 classes Android: ThreeTenABP
- 问题