Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java DateTimeFormatter parsing with special characters

Tags:

java

datetime

I'm having some troubles getting my format right for using DataTimeFormatter to parse a date time String in the format of:

20200915095318.883[-4:EDT]

I have a DateTimeFormatter pattern that works to produce this format, but it doesn't work to parse the same String. That pattern is:

yyyyMMddHHmmss.SSS'['x':'z']'

If there are other libraries for DateTime parsing that are more appropriate for this type of need I'll happily consider those as well. Right now my solution is a one off regex matcher for when I encounter this DateTime String and to manually build its parts. Which is gross.

like image 688
Scott Lindner Avatar asked Sep 25 '20 12:09

Scott Lindner


2 Answers

java.time, the modern Java date and time API that I think you are already using, is indeed the best library for the job. This works since Java 9:

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .appendPattern("uuuuMMddHHmmss")
            .appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true)
            .appendLiteral('[')
            .appendOffset("+Hmm", "+0")
            .appendLiteral(':')
            .appendZoneText(TextStyle.SHORT)
            .appendLiteral(']')
            .toFormatter(Locale.ENGLISH);
    
    String s = "20200915095318.883[-4:EDT]";
    
    OffsetDateTime odt = OffsetDateTime.parse(s, formatter);
    ZonedDateTime zdt = ZonedDateTime.parse(s, formatter);
    
    if (odt.getOffset().equals(zdt.getOffset())) {
        System.out.println(odt);
        System.out.println(zdt);
    } else {
        System.out.println("Something’s wrong here");
    }

Output is:

2020-09-15T09:53:18.883-04:00
2020-09-15T09:53:18.883-04:00[America/New_York]

Parsing into an OffsetDateTime uses the offset, -4, while parsing into a ZonedDateTime uses the time zone abbreviation, EDT. I check that the two agree about the offset because else I would not know which of them to believe. In your example string they do agree.

I am passing +Hmm as pattern to appendOffset(). Other choices include +H, +H:mm, +Hmmss and +H:mm:ss. Lower case mm and ss mean that minutes and seconds of the offset are optional. You should choose based on how an offset would look like if it is not a whole number of hours.

What do I mean by since Java 9? java.time, DateTimeFormatterBuilder and its appendOffset method are all in Java 8, but only since Java 9 does that method accept a pattern with just one H for one-digit hour in it.

like image 118
Ole V.V. Avatar answered Nov 15 '22 00:11

Ole V.V.


Your only problem is that the -4 in your string needs a leading zero, as @deHaar indicated in his comment, i.e.

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss.SSS'['x':'z']'");
LocalDateTime ldt = LocalDateTime.parse("20200915095318.883[-04:EDT]", formatter);
like image 36
Abra Avatar answered Nov 14 '22 23:11

Abra