Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.3k views
in Technique[技术] by (71.8m points)

datetime format - Java DateTimeFormatterBuilder with optional pattern results in DateTimeParseException

Goal

Provide a flexible parser for LocalDate instances that can handle input in one of the following formats:

  • yyyy
  • yyyyMM
  • yyyyMMdd

Implementation Attempt

The following class attempts to handle both the first and the second pattern. Parsing works for the year input, but year + month results in the exception outlined below.

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;

public class DateTest {

    public static void main(String[] args) {
        DateTimeFormatter parser = new DateTimeFormatterBuilder()
        .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
        .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
        .appendPattern("yyyy")
        .optionalStart().appendPattern("MM").optionalEnd().toFormatter();

        System.out.println(parser.parse("2014", LocalDate::from)); // Works
        System.out.println(parser.parse("201411", LocalDate::from)); // Fails
    }
}

The second parse() attempt results in the following exception:

Exception in thread "main" java.time.format.DateTimeParseException: Text '201411' could not be parsed at index 0
at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949)
at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)

I think my understanding of how optional partial patterns work is lacking. Is my goal of one parser with a flexible format even achievable, or do I need to check on input length and select from a list of parsers? As always, help is appreciated.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Here is the solution. You can define possible patterns inside appendPattern(). And to optional put defaults.

   DateTimeFormatter parser = new DateTimeFormatterBuilder()
            .appendPattern("[yyyy][yyyyMM][yyyyMMdd]")
            .optionalStart()
              .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
              .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
            .optionalEnd()
            .toFormatter();
    System.out.println(parser.parse("2014",LocalDate::from)); // Works
    System.out.println(parser.parse("201411",LocalDate::from)); // Works
    System.out.println(parser.parse("20141102",LocalDate::from)); // Works

The output is

2014-01-01
2014-11-01
2014-11-02

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...