有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java DateTimeFormatter无效日期在LocalDateTime之后进行调整。作语法分析

我一直在努力研究Java8如何将字符串解析为LocalDateTime的实例。我在为从字符串到LocalDateTime的转换编写单元测试时注意到了这一点

下面是一个方法示例(不是实际的),自Java8发布以来,我已经使用了一段时间

private void convertToLocalDateTime(String s) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-M-d HH:mm")
        .withResolverStyle(ResolverStyle.STRICT);
    try {
        LocalDateTime ldt = LocalDateTime.parse(s, formatter);
        System.out.println("s: " + s + " -> ldt: " + ldt.toString());
    } catch(DateTimeParseException e) {
        System.out.println("s: " + s + " -> The field is not a valid date.");
    }
}

在这里,您可以看到我添加了两个s.o.p来显示显示。这里是一个显示示例

s: 2016-06-31 11:00 -> ldt: 2016-06-30T11:00
s: 2016-07-31 11:00 -> ldt: 2016-07-31T11:00
s: 2016-08-31 11:00 -> ldt: 2016-08-31T11:00
s: 2016-09-31 11:00 -> ldt: 2016-09-30T11:00
s: 2016-10-31 11:00 -> ldt: 2016-10-31T11:00
s: 2016-11-31 11:00 -> ldt: 2016-11-30T11:00
s: 2016-12-31 11:00 -> ldt: 2016-12-31T11:00
s: 2016-11-0 11:00 -> The field is not a valid date.
s: 2016-11-1 11:00 -> ldt: 2016-11-01T11:00
s: 2016-11-15 11:00 -> ldt: 2016-11-15T11:00
s: 2016-11-30 11:00 -> ldt: 2016-11-30T11:00
s: 2016-11-31 11:00 -> ldt: 2016-11-30T11:00
s: 2016-11-32 11:00 -> The field is not a valid date.

正如您所看到的,一切似乎都是正确的,但是日期不正确的日期(如11月31日)将转换为11月30日。我很困惑,因为我一直在使用这种方法,而我今天才注意到这一点

在做了一些研究之后,我发现有一种“解析器风格”。这里是来自java doc的文本

public static DateTimeFormatter ofPattern(String pattern) Creates a formatter using the specified pattern. This method will create a formatter based on a simple pattern of letters and symbols as described in the class documentation. For example, d MMM uuuu will format 2011-12-03 as '3 Dec 2011'.

The formatter will use the default FORMAT locale. This can be changed using withLocale(Locale) on the returned formatter Alternatively use the ofPattern(String, Locale) variant of this method.

The returned formatter has no override chronology or zone. It uses SMART resolver style.

我就像“乌特”。显然,有严格、聪明和宽容

所以,我选择了STRICTconvertToLocalDateTime(String)方法主体中的第一行用

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-M-d HH:mm")
    .withResolverStyle(ResolverStyle.STRICT);

然而,这给出了以下几点

s: 2016-01-31 11:00 -> The field is not a valid date.
s: 2016-02-31 11:00 -> The field is not a valid date.
s: 2016-03-31 11:00 -> The field is not a valid date.
s: 2016-04-31 11:00 -> The field is not a valid date.
s: 2016-05-31 11:00 -> The field is not a valid date.
s: 2016-06-31 11:00 -> The field is not a valid date.
s: 2016-07-31 11:00 -> The field is not a valid date.
s: 2016-08-31 11:00 -> The field is not a valid date.
s: 2016-09-31 11:00 -> The field is not a valid date.
s: 2016-10-31 11:00 -> The field is not a valid date.
s: 2016-11-31 11:00 -> The field is not a valid date.
s: 2016-12-31 11:00 -> The field is not a valid date.
s: 2016-11-0 11:00 -> The field is not a valid date.
s: 2016-11-1 11:00 -> The field is not a valid date.
s: 2016-11-15 11:00 -> The field is not a valid date.
s: 2016-11-30 11:00 -> The field is not a valid date.
s: 2016-11-31 11:00 -> The field is not a valid date.
s: 2016-11-32 11:00 -> The field is not a valid date.

这些突然都不起作用了。即使使用yyyy-MM-dd HH:mm也没有帮助。我怀疑STRICT不能很好地处理自定义格式字符串

因此,我的问题是:有没有办法克服“11月31日”问题,即它不会在11月30日得到解决?(对于其他可能的日期,ofc类似)或者如果解析器调整了值,返回false的方法

或者我必须自己评估生成的LocalDateTime实例吗


共 (1) 个答案

  1. # 1 楼答案

    你的困惑是有道理的。我发现事实上,模式"yyyy-MM-dd HH:mm"DateTimeFormatter使用STRICT解析器样式,甚至拒绝它自己格式化的日期字符串

    经进一步调查,这似乎与{}在“年”和“纪年”之间的新区别有关(相对于公认的{})。对于DateTimeFormatter'y'格式符号表示后者;前者对应于格式字母'u'。事实证明,如果我使用格式字符串"uuuu-MM-dd HH:mm",您的程序将生成您似乎要查找的输出:

    private void convertToLocalDateTime(String s) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-M-d HH:mm")
            .withResolverStyle(ResolverStyle.STRICT);
        try {
            LocalDateTime ldt = LocalDateTime.parse(s, formatter);
            System.out.println("s: " + s + " -> ldt: " + ldt.toString());
        } catch(DateTimeParseException e) {
            System.out.println("s: " + s + " -> The field is not a valid date.");
        }
    }
    

    单位数与双位数字段对解析没有影响

    This question论述了“年”和“纪年”之间的区别。虽然我理解这一区别,但我认为实现DateTimeFormatterSimpleDateFormat不必要的不兼容是一个糟糕的选择,因为它们的一些最常见的用途。我想我应该把'u'y的意思互换一下,以避免你遇到的那种问题。然而,很明显,这个API的设计者不同意,这是所有的水下桥在这一点上