2

I'm trying to parse "20140726080320+0400" using "yyyyMMddHHmmssZ" format as follows:

System.out.println("********************" + OffsetDateTime
    .parse("20140726080320+0400",
        DateTimeFormatter.ofPattern("yyyyMMddHHmmssZ").withChronology(IsoChronology.INSTANCE).withResolverStyle(STRICT))
    .toEpochSecond()); 

I keep running into this exception:

java.time.format.DateTimeParseException: Text '20140726080320+0400' could not be parsed: Unable to obtain OffsetDateTime from TemporalAccessor: {OffsetSeconds=14400, DayOfMonth=26, YearOfEra=2014, MonthOfYear=7},ISO resolved to 08:03:20 of type java.time.format.Parsed
    at java.time.format.Parsed.getLong(Parsed.java:203)
    at java.time.Instant.from(Instant.java:373)
    at java.time.OffsetDateTime.from(OffsetDateTime.java:365)
    at java.time.format.Parsed.query(Parsed.java:226)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
    at java.time.OffsetDateTime.parse(OffsetDateTime.java:402)

What am I doing wrong?

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
Gaurav
  • 157
  • 1
  • 2
  • 8
  • I'd have to look it up again but I'd say your timezone format `Z` is wrong. – Thomas Jan 15 '18 at 12:55
  • From DateTimeFormatter.java: `* Symbol Meaning Presentation Examples` `* Z zone-offset offset-Z +0000; -0800; -08:00;` – Gaurav Jan 15 '18 at 12:58
  • In https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html there are 3 possibilities for zone offsets: Z, X and x. Perhaps XX or xx works better, like described under **Offset X and x:** – D. Braun Jan 15 '18 at 13:25
  • [How to reproduce (ideone)](https://www.ideone.com/ZoOW1t) – Ole V.V. Jan 15 '18 at 15:07

3 Answers3

3

yyyy in the format pattern string is for year of era. Strictly speaking, 2014 could denote 2014 BCE (“before Christ”) or 2014 CE (“anno Domini”). Apparently the formatter with strict resolver style objects to this ambiguity.

A solution is to use uuuu for year. This is a signed year where 0 means 1 BCE, -1 means 2 BCE etc. So there is no ambiguity:

    System.out.println("********************"
            + OffsetDateTime.parse("20140726080320+0400",
                                DateTimeFormatter.ofPattern("uuuuMMddHHmmssZ")
                                        .withChronology(IsoChronology.INSTANCE)
                                        .withResolverStyle(STRICT))
                        .toEpochSecond());

This prints

********************1406347400

This is related to the way IsoChronology resolves the date for different resolver styles, as described in the javadoc:

If only the YEAR_OF_ERA is present, and the mode is smart or lenient, then the current era (CE/AD) is assumed. In strict mode, no era is assumed and the YEAR_OF_ERA is left untouched.

Community
  • 1
  • 1
Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
2

Maybe my answer is outdated, but I just dealt with a similar problem -)

if you want to use strict mode, and keep using "yyyy" instead of "uuuu", then you need to add an indication of the ERA. I used the default value, like this:

    OffsetDateTime.parse("20140726080320+0400", 
     new DateTimeFormatterBuilder()
         .appendPattern("yyyyMMddHHmmssZ")
         .parseDefaulting(ChronoField.ERA, 1)
         .toFormatter()
         .withResolverStyle(ResolverStyle.STRICT)
);

This code works correctly. I hope this helps someone.

LVA
  • 21
  • 1
0

Try this:

LocalDateTime.parse("20140726080320+0400",
    new DateTimeFormatterBuilder().appendPattern("yyyyMMddHHmmssZ").toFormatter())
.atOffset(ZoneOffset.UTC)

The return:

2014-07-26T08:03:20


This is wrong because it ignores the offset (+0400) and then set the date/time to UTC - which will give an incorrect value for epochSecond

Community
  • 1
  • 1
laaf
  • 131
  • 7
  • Wouldn’t it be simpler just to remove the `.withResolverStyle(STRICT)` from the OP’s code? However, I suspect the OP put it in there for a reason, so best if we can find a solution that uses a strict formatter. – Ole V.V. Jan 15 '18 at 14:51