How to handle all zone offsets in one Java 8 DateTimeFormater

I need to create DateTimeFormatter

for the following valid dates.

  String date1 = "2017-06-20T17:25:28";
  String date2 = "2017-06-20T17:25:28.477777";
  String date3 = "2017-06-20T17:25:28.477777Z";
  String date4 = "2017-06-20T17:25:28.477777UTC";
  String date5 = "2017-06-20T17:25:28.477777-05";
  String date6 = "2017-06-20T17:25:28.477777+05";
  String date7 = "2017-06-20T17:25:28.477777+05:30";
  String date8 = "2017-06-20T17:25:28.477777-05:30";
  String date9 = "2017-06-20T17:25:28.477777+0530";
  String date10 = "2017-06-20T17:25:28.477777-0530";

      

I have tried the following date time format but it fails for the last two dates ( date9

, date10

).

private static final DateTimeFormatter DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()
    .appendPattern("yyyy-MM-dd'T'HH:mm:ss")
    .appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true)
                        .optionalStart().appendZoneId().optionalEnd()
                        .optionalStart().appendOffset("+HH", "+00").optionalEnd()
                        .optionalStart().appendOffset("+HH:mm", "+00:00").optionalEnd()
                        .optionalStart().appendOffset("+HHmm", "+0000").optionalEnd().toFormatter();

      

All dates from date1

to date8

work fine, but when trying to parse the last two dates, I get DateTimeParseException

:

Exception in thread "main" java.time.format.DateTimeParseException: text '2017-06-20T17: 25: 28.477777 + 0530' could not be parsed, text without text found at index 29

For parsing the date used below.

LocalDateTime.parse(date1, DATE_TIME_FORMATTER);

      

Valid template for offset From OffsetIdPrinterParser

:

static final class OffsetIdPrinterParser implements DateTimePrinterParser {
        static final String[] PATTERNS = new String[] {
            "+HH", "+HHmm", "+HH:mm", "+HHMM", "+HH:MM", "+HHMMss", "+HH:MM:ss", "+HHMMSS", "+HH:MM:SS",
        };  // order used in pattern builder

      

I cannot figure out when I am using the correct ZoneOffset templates why my last two dates are failing.

+3


source to share


2 answers


Another alternative is to use optional sections separated by character []

and appropriate offset patterns ( VV

and x

):

DATE_TIME_FORMATTER = DateTimeFormatter
                         // pattern with optional sections: fraction of seconds and offsets
                         .ofPattern("yyyy-MM-dd'T'HH:mm:ss[.SSSSSS][VV][x][xx][xxx]");

      

Each pair is []

equivalent to one section optionalStart

and optionalEnd

. Note that I also had to include the capitalization S

(fraction of a second) as optional to parse the case where this field is missing.

Other templates ( VV

and x

) correspond to different shifts that you need. From the javadoc :

Pattern  Count  Equivalent builder methods
-------  -----  --------------------------
  VV      2      appendZoneId()
  x       1      appendOffset("+HHmm","+00")
  xx      2      appendOffset("+HHMM","+0000")
  xxx     3      appendOffset("+HH:MM","+00:00")

      



This works for all of your entry dates.


The only difference is that it [.SSSSSS]

accepts exactly 6 digits in a fraction of a second field (or zero digits, as this is an optional section), whereas it appendFraction

accepts any number between 0 and 6 digits. To get exactly the same behavior, you should use DateTimeFormatterBuilder

:

DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()
    // date and time
    .appendPattern("yyyy-MM-dd'T'HH:mm:ss")
    // fraction of seconds, from 0 to 6 digits
    .appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true)
    // optional offset patterns
    .appendPattern("[VV][x][xx][xxx]")
    .toFormatter();

      

+2


source


Just change the order of your additional sections:

private static final DateTimeFormatter DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()
        .appendPattern("yyyy-MM-dd'T'HH:mm:ss")
        .appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true)
        .optionalStart().appendZoneId().optionalEnd()
        .optionalStart().appendOffset("+HHmm", "+0000").optionalEnd()
        .optionalStart().appendOffset("+HH:mm", "+00:00").optionalEnd()
        .optionalStart().appendOffset("+HH", "+00").optionalEnd()
        .toFormatter();

      



This analyzes all of your 10 sample time lines.

I'm not really sure why it works. I suppose he is now trying +HHmm

to +HH

, which will ensure he gets four digits if there are four, instead of leaving the last two unpacked.

+5


source







All Articles