首页 > 解决方案 > DateTimeFormatter.parse(s) 在到达 s 末尾时抛出:为什么?

问题描述

我一直在尝试使用 DateTimeFormatter 来解析“20141112152340”形式的日期/时间字符串。当我调用 formatter.parse(input); 它引发了一个例外:

java.time.format.DateTimeParseException:无法在索引 14 处解析文本“20141112152340”

这是一个最小的完整复制器:

package com.example.minimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.ResolverStyle;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;

public class Reproducer {
    public static void main(String[] args) {
        DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .appendValue(ChronoField.YEAR) // 4
            .appendValue(ChronoField.MONTH_OF_YEAR) // 2
            .appendValue(ChronoField.DAY_OF_MONTH) // 2
            .appendValue(ChronoField.HOUR_OF_DAY) // 2
            .appendValue(ChronoField.MINUTE_OF_HOUR) // 2
            .appendValue(ChronoField.SECOND_OF_MINUTE) // 2
            .toFormatter()
            // Using the default ResolverStyle appears to make no difference.
            .withResolverStyle(ResolverStyle.STRICT); // expect 14 characters
        String input = "20141112152340";
        System.out.printf("length of input is %02d:               [%s]; format is %s\n", input.length(), input, formatter.toString());
        // When the minute of hour is < 10, it is rendered without zero-padding.   Perhaps this
        // is related.  But, the same problem is reproducible on input strings that do not contain zeroes.
        System.out.printf("Current local time in that format is [%s]\n", formatter.format(LocalDateTime.now()));
        // The following line throws java.time.format.DateTimeParseException: Text '20140816152340' could not be parsed at index 14
        TemporalAccessor parsed = formatter.parse(input);
        // NOTREACHED
        LocalDateTime stamp = parsed.query(LocalDateTime::from);
        System.out.println("Time stamp is " + stamp.toString());
    }
}

这是该程序的输出:

length of input is 14:               [20141112152340]; format is Value(Year)Value(MonthOfYear)Value(DayOfMonth)Value(HourOfDay)Value(MinuteOfHour)Value(SecondOfMinute)
Current local time in that format is [20191010183335]
Exception in thread "main" java.time.format.DateTimeParseException: Text '20141112152340' could not be parsed at index 14
    at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1874)
    at com.example.minimal.Reproducer.main(Reproducer.java:28)

据我所知,解析器在它到达字符串末尾的那一刻就开始了。由于它正在寻找更多数据而发生这种情况,我尝试将解析器样式从默认切换为严格,但这似乎没有什么区别。

我的问题是,为什么会发生这种情况,以及如何更正我的代码以便它可以解析这个日期/时间表示?

标签: java

解决方案


以下格式化程序对我有用:

DateTimeFormatter.ofPattern("yyyyMMddHHmmss");

toString()两种格式化程序都揭示了差异:

Value(Year)Value(MonthOfYear)Value(DayOfMonth)Value(HourOfDay)Value(MinuteOfHour)Value(SecondOfMinute)

对比

Value(YearOfEra,4,19,EXCEEDS_PAD)Value(MonthOfYear,2)Value(DayOfMonth,2)Value(HourOfDay,2)Value(MinuteOfHour,2)Value(SecondOfMinute,2)

如您所见,第二个格式化程序,即工作版本,似乎有明确的字段宽度以及明确的SignStyle

我们可以使用构建器创建相同的格式化程序:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
        .appendValue(ChronoField.YEAR_OF_ERA, 4, 19, SignStyle.EXCEEDS_PAD)
        .appendValue(ChronoField.MONTH_OF_YEAR, 2)
        .appendValue(ChronoField.DAY_OF_MONTH, 2)
        .appendValue(ChronoField.HOUR_OF_DAY, 2)
        .appendValue(ChronoField.MINUTE_OF_HOUR, 2)
        .appendValue(ChronoField.SECOND_OF_MINUTE, 2)
        .toFormatter()
        .withResolverStyle(ResolverStyle.STRICT);

但是,看起来您可以用YEAR_OF_ERA类似YEAR的结果替换。


推荐阅读