“日期时间格式化程序”,用于处理小数秒的句号或逗号



在java.time类中,我们如何为DateTimeFormatter指定一个格式模式,允许句号(.((句点或点(或逗号(,(作为小数秒的分隔符?

例如,以下内容适用于解析以 .0Z 结尾的输入日期值或以 20090813145607.0Z20090813145607,0Z 结尾的,0Z

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

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

20090813145607,0.0Z

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

DecimalStyle

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

这个问题很重要,因为ISO 8601标准建议使用逗号,但允许句号。这两种方法在实践中都很常用。

Instant不能容忍逗号

也许这种逗号和/或点作为小数点的容差在java.time中是不可能的。

我用Java 8 Update 102尝试了以下代码。第一个带有句号(点(的输入成功,而带有逗号的第二个输入失败。

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

在我的经验中,点与逗号更常见。RFC3339仅像 XML 架构一样使用点。该点不再是"首选"(根据维基百科(:

小数点,逗号或点(没有任何首选项 在第二十二届大会 CGPM 第 10 号决议中指出 2003,[16]但根据ISO优先使用逗号 8601:2004(

鉴于所有这些,JSR-310更喜欢一个点。

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

无法解析点或逗号。这被跟踪为 JDK-8132536,它在解析中处理了一般的"或"概念。

使用ISO_INSTANT解析时刻,该表示"不使用本地化的十进制样式"。

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

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 子类,但这应该对你进行排序。

(基于我有问题的评论(

如果"日期时间格式化程序"允许这种"或"模式,我会发现。

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

  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. 通过将倒数第 3 个字符替换为 . 来"规范化"输入,如果它是一个,,您可以使用一个格式化程序。 例如

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

最新更新