【问题标题】:`DateTimeFormatter` to handle either a FULL STOP or COMMA in fractional second`DateTimeFormatter` 在小数秒内处理 FULL STOP 或 COMMA
【发布时间】:2016-08-11 01:39:13
【问题描述】:

java.time 类中,我们如何为DateTimeFormatter 指定格式模式,允许使用句号(.)(句点或点)或逗号(,)作为分隔符几分之一秒?

例如,以下方法适用于在20090813145607.0Z20090813145607,0Z 中解析以.0Z,0Z 结尾的输入日期值。

String input = "20090813145607.0Z";
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "uuuuMMddHHmmss[,S][.S]X" );

但是对于打印,输出包含 both,生成一对重复的小数秒。

20090813145607,0.0Z

所以我推断我在格式化模式中使用[,S][.S] 不是获得此功能的正确方法。

DecimalStyle

我尝试使用传递DecimalStyleDateTimeFormatter::withDecimalStyle 方法,但在我的实验中未能达到我的预期。该文档并未真正解释其预期行为。

这个问题很重要,因为ISO 8601 标准建议使用 COMMA,但允许使用 FULL STOP。实践中常用的。

Instant 不能容忍逗号

也许这种逗号和/或点的容忍度为decimal mark 在java.time 中是不可能的。

我在 Java 8 Update 102 中尝试了以下代码。带有 FULL STOP(点)的第一个输入成功,而带有 COMMA 的第二个输入失败。

String inputDot = "2016-01-02T12:34:56.7Z";  // Succeeds.
Instant instantDot = Instant.parse ( inputDot );

String inputComma = "2016-01-02T12:34:56,7Z";  // Fails. Throws a DateTimeParseException.
Instant instantComma = Instant.parse ( inputComma );

【问题讨论】:

  • 澄清一下,你想要一个DateTimeFormatter 可以处理两种格式的解析,但只有一个格式的格式?
  • 我想知道“DateTimeFormatter”是否允许这种“或”模式。我能想到的两种解决方法是 1. 制作 2 格式化程序,一种用于,,一种用于.,如果第一个无法解析,请使用第二个。或者 2,通过将倒数第三个字符替换为 .(如果它是 ,)来“规范化”输入,并且您可以使用单个格式化程序
  • @SotiriosDelimanolis 是的,我想要一个既适用于输入又适用于输出的格式化程序。我假设 java.time 类对命令和点都有这样的双向支持,但假设错误。请参阅我的编辑,显示 Instant.parse 可以处理点但不能处理逗号。
  • 在 Java 时代对有缺陷的 ISO8601 支持的有趣发现。如果它可以作为一个问题提出,那就太好了:)
  • 我已经在 bugs.java.com 上提交了“Review ID: JI-9042753”。在审核之前可能不会出现在此处。

标签: java parsing datetime-format java-time date-parsing


【解决方案1】:

在点与逗号方面,根据我的经验,点比逗号更常见。 RFC3339 仅使用点,XML schema 也是如此。点不再是“首选”(根据wikipedia):

小数点,逗号或点(没有任何偏好 在第 22 届大会 CGPM 的第 10 号决议中指出 2003,[16] 但根据 ISO 优先使用逗号 8601:2004)

鉴于这一切,JSR-310 更喜欢点。

DecimalStyle 类确实提供了一些控制,其中DateTimeFormatterBuilder.appendFraction 方法与true 一起使用以从DecimalStyle 输出小数点。

解析点或逗号是不可能的。这被跟踪为JDK-8132536,它处理解析中的一般“或”概念。

使用 ISO_INSTANT 解析实例,表示“未使用本地化十进制样式”。

因此,JSR-310 的格式化程序不能做你想做的事。

【讨论】:

  • 关于你的说法“点不再是首选”,维基百科提到了在 2003 年发生这种说法的会议,但官方的 ISO-paper 是从 2004 年开始的,所以我认为,逗号仍然是官方的在纯 ISO 的上下文中首选(尽管在 XML 模式等 ISO 衍生产品中甚至被禁止)。
【解决方案2】:
String fmt1 = "uuuuMMddHHmmss,SX";
String fmt2 = "uuuuMMddHHmmss.SX";
DateTimeFormatter f = DateTimeFormatter.ofPattern(fmt1);
TemporalAccessor dateObject = null;
try {
    dateObject = f.parse("20090813145607.0Z");
} catch (DateTimeParseException e) {
    f = DateTimeFormatter.ofPattern(fmt2);
    try {
        dateObject = f.parse(input);
    } catch (DateTimeParseException e1) { 
        throw new IllegalArgumentException("invalid format "+input);
    } 
} 

也许使用不同的 RuntimeException 子类,但这应该对你进行排序。

【讨论】:

    【解决方案3】:

    (根据我的评论)

    我想知道“DateTimeFormatter”是否允许这种“或”模式。

    我能想到的两种解决方法是

    1. 使用多个格式化程序。例如。一个用于,,一个用于.,如果第一个解析失败,则使用第二个。

      伪代码

      List<DateTimeFormatter> formatters = Arrays.asList(
              DateTimeFormatter.ofPattern( "uuuuMMddHHmmss.SX" ),
              DateTimeFormatter.ofPattern( "uuuuMMddHHmmss,SX" ));
      
      TemporalAccessor result = null;
      for (DateTimeFormatter f: formatters) {
          try {
              result = f.parse(input);
              break;
          } catch(DateTimeParseException ignored) {
          }
      }
      if (result == null) {
          throw new WhateverException();
      }
      
    2. 如果输入是,,则通过用. 替换倒数第三个字符来“规范化”输入,并且您可以使用一个格式化程序。例如

      f = DateTimeFormatter.ofPattern( "uuuuMMddHHmmss.SX" )
      result = f.parse(input.matches(",..$")
                       ? input.replaceAll("^(.*),(..)$", "\\1.\\2")
                       : input);
      

    【讨论】:

      猜你喜欢
      • 2017-11-06
      • 2019-12-24
      • 2018-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-04
      • 1970-01-01
      相关资源
      最近更新 更多