The accepted answer is fine. I just have two things to add:
- You can parse the string with the invalid second value of 60 by using
ResolverStyle.LENIENT
.
- Since Jon Skeet in a comment mentioned a possible leap second: It’s not a valid leap second. java.time does support the parsing of a (valid) leap second.
Parsing your string
DateTimeFormatter lenientFormatter
= DateTimeFormatter.ISO_OFFSET_DATE_TIME
.withResolverStyle(ResolverStyle.LENIENT);
String dateString = "2018-12-04T08:06:60Z";
Instant myInstant = lenientFormatter.parse(dateString, Instant::from);
System.out.println(myInstant);
Output:
2018-12-04T08:07:00Z
So the overflowing second value of 60 has been rolled into a full minute.
By the way, javax.xml.bind.DatatypeConverter.parseDateTime
parses into a Calendar
(not a Date
), which is how the returned object can in fact hold a second value of 60. It seems that it generally accepts a second value of 60, but throws an exception on 61.
Parsing a valid leap second
This does in no way answer your question, but I thought that it might be useful for future readers. A leap second is always the last second of the day, so 23:59:60. An Instant
cannot hold this value, but you can query whether one was parsed. It’s supported via DateTimeFormatterBuilder.appendInstant(),
and DateTimeFormatter.parsedLeapSecond()
.
DateTimeFormatter leapSecondFormatter = new DateTimeFormatterBuilder()
.appendInstant()
.toFormatter();
Instant myInstant
= leapSecondFormatter.parse("2018-12-04T23:59:60Z", Instant::from);
System.out.println(myInstant);
TemporalAccessor parsed = leapSecondFormatter.parse("2018-12-04T23:59:60Z");
System.out.println("Instant: " + parsed.query(Instant::from));
System.out.println("Was a leap second parsed? "
+ parsed.query(DateTimeFormatter.parsedLeapSecond()));
Output:
2018-12-04T23:59:59Z
Instant: 2018-12-04T23:59:59Z
Was a leap second parsed? true
I don’t know why it had to be this complicated, but it works.
Link: Documentation of DateTimeFormatter.parsedLeapSecond
java.util.Calendar
is lenient by default so I guess it accepts 60 seconds. – Rufusjava.time
supports leap seconds. (And I don't believe that's a valid leap second.) – Sahib