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。

链接