java 中的日期格式化程序

Dateformatter in java

我正在使用以下代码来格式化毫秒分辨率日期字符串。它适用于 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]

我能看到的唯一可能的问题是您传递的毫秒数不正确,程序不知道该怎么做。

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

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

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

你唯一的问题是你为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'");

因为 date 字符串中使用的 Z 意味着 "zero hour offset" 所以你只需要在你的模式中将它作为 'Z' 传递。

这是 a working demo,格式正确。

编辑:

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

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

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

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);      
          }

    }
}

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

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

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

已经正确诊断并解释了你得到异常的原因。

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

链接