2

我正在使用下面的代码来格式化毫秒分辨率的日期字符串。它适用于2018-09-14T13:05:21.329Z但不适用2018-09-14T13:05:21.3Z。有人可以提出原因以及如何纠正吗?

DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
SimpleDateFormat sdfDestination = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
    Date parsedDate = formatter.parse(date);
    String destDate = sdfDestination.format(parsedDate);
    return destDate;
} catch (java.text.ParseException parseException) {
    logger.error("Parse Exception occured while converting publication time to date "
            + "format 'yyyy-MM-dd HH:mm:ss'", parseException);
}

我得到以下异常:

java.text.ParseException: Unparseable date: "2018-09-14T13:05:21.3Z"
    at java.text.DateFormat.parse(Unknown Source) ~[na:1.8.0_181]
    at com.noordpool.api.implementation.utility.Utility.parseDate(Utility.java:136) [classes/:na]
    at com.noordpool.api.implementation.utility.Utility.parseMessage(Utility.java:77) [classes/:na]
4

4 回答 4

1

java.time

    DateTimeFormatter dtfDestination
            = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
    String date = "2018-09-14T13:05:21.3Z";
    String destDate = Instant.parse(date)
            .atZone(ZoneId.of("Indian/Comoro"))
            .format(dtfDestination);
    System.out.println(destDate);

此片段的输出是:

2018-09-14 16:05:21

如果不是印度/科摩罗,请替换您的正确时区,因为正确的输出取决于使用正确的时区。如果要使用 JVM 的默认时区,请指定ZoneId.systemDefault(),但请注意,可以随时从程序的其他部分或在同一 JVM 中运行的其他程序更改默认值。

我正在利用这样一个事实,即您的字符串"2018-09-14T13:05:21.3Z"是 ISO 8601 格式,java.time 的类将其解析为默认格式,即没有任何显式格式化程序。Instant.parse接受从 0 到 9 秒的任何小数,所以给它一个只有 1 个小数的字符串是没有问题的,就像你做的那样。相比之下,老式的SimpleDateFormat无法以完全精度解析秒上的 1 个小数,因为它需要模式字母(大写)S来表示毫秒,因此.3将被解析为 3 毫秒,而不是十分之三秒,因为它方法。

Jahnavi Paliwal已经正确诊断并解释了您遇到异常的原因。

您使用的日期时间类DateFormatSimpleDateFormatDate都早已过时,SimpleDateFormat尤其是出了名的麻烦。由于您似乎使用的是 Java 8(即使您没有使用),我建议您完全避免使用这些类并改用 java.time。

链接

于 2018-09-14T15:41:32.330 回答
1

我能看到的唯一可能的问题是您错误地以毫秒为单位传递,并且程序不知道该怎么做。

所以格式化程序的最后一部分用毫秒和时区表示为 .SSSX

但是它如何评估 3Z 的输入呢?我的意思是,你是说它是 300 时区 Z,还是说它是 003 时区 Z,或者更糟糕的是,尝试将其解析为 3Z,希望你看到你不能将“3Z”变成一个数字。

为了解决这个问题,我将验证您输入的“日期”并确保毫秒部分始终为 3 位数长,这消除了歧义,程序始终知道您的意思是“300 毫秒,时区 Z”。

于 2018-09-14T13:35:09.863 回答
1

您唯一的问题是您使用了错误的模式SimpleDateFormat,您需要更改:

DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");

至:

DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

因为字符串中Z使用的date意思是“零小时偏移”,所以你只需要像'Z'在你的模式中一样传递它。

这是一个具有正确模式的工作演示。

编辑:

为了让不同的语言环境和时区工作,您需要在Locale创建SimpleDateFormat实例时使用适当的,这应该是代码:

DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
于 2018-09-14T13:41:39.793 回答
1

java 8 中存在一个问题,您使用格式化程序指定的字符数应该完全匹配(文档中未指定)。您可以使用三种不同的格式化程序并使用嵌套异常,如下所示:

DateFormat format1 = new SimpleDateFormat("y-M-d'T'H:m:s.SX");
DateFormat format2 = new SimpleDateFormat("y-M-d'T'H:m:s.SSX");
DateFormat format3 = new SimpleDateFormat("y-M-d'T'H:m:s.SSSX");
Date parsedDate;

try {
    // Parsing for the case - 2018-09-14T13:05:21.3Z 
    parsedDate  = format1.parse(date); 
} catch (ParseException e1) {

    try {
         // Parsing for the case - 2018-09-14T13:05:21.32Z 
         parsedDate = format2.parse(date); 
    } catch (ParseException e2) {

          try {
              // Parsing for the case - 2018-09-14T13:05:21.329Z 
              parsedDate = format3.parse(date);
          } catch (ParseException e2) {
             //The input date format is wrong
             logger.error("Wrong format for date - " + date);      
          }

    }
}
于 2018-09-14T13:44:45.340 回答