Reputation: 61
I have a date string which I want to parse as Instant
48962-08-06T23:16:59.000Z
but unable to do as most of standard DateTimeFormatter rules are not supporting it.
Ref: https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html
Here is what I was trying to do, using my custom formatter
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendValue(YEAR, 5, 10, SignStyle.EXCEEDS_PAD)
.appendLiteral('-')
.appendValue(MONTH_OF_YEAR, 2)
.appendLiteral('-')
.appendValue(DAY_OF_MONTH, 2)
.appendLiteral('T')
.appendValue(HOUR_OF_DAY, 2).appendLiteral(':')
.appendValue(MINUTE_OF_HOUR, 2).appendLiteral(':')
.appendValue(SECOND_OF_MINUTE, 2)
.appendFraction(NANO_OF_SECOND, 0, 9, true)
.appendLiteral('Z')
.toFormatter();
Instant value = Instant.from(formatter.parse("48962-08-06T23:16:59.000Z"));
But it fails with Unable to obtain Instant from TemporalAccessor: {},ISO resolved to +48962-08-06T23:16:59 of type java.time.format.Parsed
Upvotes: 2
Views: 430
Reputation: 86282
I agree with you that the nice solution is using a builder. The following one parses years with both 4 and 5 digits:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR, 4, 5, SignStyle.NOT_NEGATIVE)
.appendPattern("-MM-dd'T'")
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.appendOffsetId()
.toFormatter();
String dateTime = "48962-08-06T23:16:59.000Z";
Instant i = formatter.parse(dateTime, Instant::from);
System.out.println(i);
Output from the snippet is:
+48962-08-06T23:16:59Z
Your basic problem is that your string doesn’t conform with ISO 8601, the standard that the classes of java.time parse as their default, that is, without any explicit formatter. Years with more than 4 digits can be allowed in ISO 8601, but then a sign is required (as you can also see in the output above).
What went wrong in your code? Joachim Sauer is correct in the comment: Hardcoding Z
as a literal is wrong. It’s an offset of 0 from UTC and needs to be parsed as an offset. Since your formatter didn’t parse any offset, it was unable to determine a point int time, an instant, from the parsed information. This was what your error message meant:
Unable to obtain Instant from TemporalAccessor: {},ISO resolved to +48962-08-06T23:16:59 of type java.time.format.Parsed
Upvotes: 3
Reputation: 18568
On my machine, the following code parses your future year:
public static void main(String[] args) {
String dateTime = "48962-08-06T23:16:59.000Z";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuuu-MM-dd'T'HH:mm:ss.SSSz");
Instant instant = Instant.from(dtf.parse(dateTime));
System.out.println(instant);
}
and outputs
+48962-08-06T23:16:59Z
I think the problem with your code is one (or both) of the lines
.appendFraction(NANO_OF_SECOND, 0, 9, true)
.appendLiteral('Z')
because the three digits after the dot and before the Z
in the String
might not be nanos of second but rather fraction of second.
And the other line might be problematic, too, but I can't really tell you why. I only know that my answer would throw an exception when the z
(lower case) in the pattern is changed to a Z
(upper case).
You could adjust that in your DateTimeFormatter
and try again, might work.
Upvotes: 4