Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DateTimeFormatter is being too strict on parsing single-digit parts

I have a format MM/dd/yyyy, so everything formatted is with leading ZERO on single digit. The problem is that on parsing I want to be able to parse both "11/25/2018" and "5/25/2018", but formatting should always return leading zeros.

I've tried using different ResolverStyle options without any luck.

Building my own specific format seems unreasonable, when you think, that it was working out of the box using SimpleDateFormat.

Would appreciate any idea, that does not involve making formatter from scratch using FormatterBuilder

like image 234
Maciej Kubiak Avatar asked May 29 '18 08:05

Maciej Kubiak


3 Answers

Use the M/d/yyyy format, because leading zeroes are ignored. MM/dd/yyyy implies that exactly two digits are required including the possible leading zero.

    DateTimeFormatter parseformat =
            DateTimeFormatter.ofPattern("M/d/yyyy");

    DateTimeFormatter outputformat = DateTimeFormatter.ofPattern("MM/dd/yyyy");

For the code segment

    String d1 = "1/1/2018";
    String d2 = "02/29/2016";
    String d3 = "4/01/2018";

    LocalDate date = LocalDate.parse(d1, parseformat);
    System.out.println(date.format(outputformat));
    date = LocalDate.parse(d2, parseformat);
    System.out.println(date.format(outputformat));
    date = LocalDate.parse(d3, parseformat);
    System.out.println(date.format(outputformat));

I ended up with

01/01/2018
02/29/2016
04/01/2018

as expected.

See the SimpleDateFormat documentation for time patterns and how they are parsed; note that "Pattern letters are usually repeated, as their number determines the exact presentation" and that "For parsing, the number of pattern letters is ignored unless it's needed to separate two adjacent fields" (here you are separating two adjacent fields).

like image 97
Ṃųỻịgǻňạcểơửṩ Avatar answered Nov 09 '22 15:11

Ṃųỻịgǻňạcểơửṩ


Use two different formats, M/d/yyyy for parsing, and MM/dd/yyyy for printing. The former will accept both single and double digit months and days, while the latter will always print double-digits, with leading zero if necessary.

SimpleDateFormat parseFormat = new SimpleDateFormat("M/d/yyyy");
SimpleDateFormat printFormat = new SimpleDateFormat("MM/dd/yyyy");

Date date1 = parseFormat.parse("4/5/2010");
Date date2 = parseFormat.parse("04/05/2010");
String output1 = printFormat.format(date1);
String output2 = printFormat.format(date2);
// output1 and output2 will be the same
like image 9
Leo Aso Avatar answered Nov 20 '22 12:11

Leo Aso


You could use the appendOptional() in Java 8 time API

DateTimeFormatter ALL_POSSIBLE_DATE_FORMAT = new DateTimeFormatterBuilder()
            .appendOptional(DateTimeFormatter.ofPattern("MM/dd/yyyy"))
            .appendOptional(DateTimeFormatter.ofPattern(("M/dd/yyyy")))
            .toFormatter();

System.out.println(LocalDate.parse("11/25/2018", ALL_POSSIBLE_DATE_FORMAT));
System.out.println(LocalDate.parse("5/25/2018", ALL_POSSIBLE_DATE_FORMAT));

Output:

2018-11-25

2018-05-25

like image 8
Deb Avatar answered Nov 20 '22 12:11

Deb