【问题标题】:Dateformatter in java [duplicate]java中的日期格式化程序[重复]
【发布时间】:2019-02-19 07:51:22
【问题描述】:

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

【问题讨论】:

标签: java string date simpledateformat dateformatter


【解决方案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'");

因为date 字符串中使用的Z 表示“零小时偏移”,所以您只需在模式中将其作为'Z' 传递。

这是 a working demo,具有正确的模式。

编辑:

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

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

【讨论】:

    【解决方案2】:

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

    这个 sn-p 的输出是:

    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。

    链接

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 分析正确。我在 Java 1.8.0_60 和 1.8.0_131 上复制了提问者的问题,但在 Java 9.0.4 上没有。由于使用 Java 8,我建议解决方案是扔掉早已过时且臭名昭著的麻烦 SImpleDateFormat 并改用 java.time:Instant.parse("2018-09-14T13:05:21.3Z")。不需要显式格式化程序。
      • 虽然在提问者的上下文中应用您的链式尝试解析时输出将符合预期,但您实际上是将问题中的示例字符串解析为等于2018-09-14T13:05:21.003ZDate,即也就是说,您已将 .3 秒解析为 3 毫秒,这确实意味着十分之三秒。不过,SimpleDateFormat 不可能做得更好。
      • 正确表述。 Java 时间是 .3 场景的更好选择,因为它意味着十分之三秒。会尝试相同的。
      【解决方案4】:

      我能看到的唯一可能的问题是,您传递的毫秒数不正确,程序不知道如何处理它。

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-26
        • 2015-06-17
        • 2021-03-06
        相关资源
        最近更新 更多