With Java 1.8.0_51 the following code (taken from Unable to obtain OffsetDateTime from TemporalAccessor)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd").withZone(ZoneId.of("Europe/Berlin"));
OffsetDateTime offsetDateTime = ZonedDateTime.parse("20151113", formatter).toOffsetDateTime();
System.out.println(offsetDateTime.format(DateTimeFormatter.ISO_DATE));
throws an exception:
java.time.format.DateTimeParseException: Text '20151113' could not be parsed: Unable to obtain ZonedDateTime from TemporalAccessor: {},ISO,Europe/Berlin resolved to 2015-11-13 of type java.time.format.Parsed
at java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:1918)
at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1853)
at java.time.ZonedDateTime.parse(ZonedDateTime.java:597)
What am I doing wrong this time?
You are forgetting to set a time.
If you compare my answer with your code, you can notice that the only difference is that the time information missing. A ZonedDateTime
contains a time information and since your current formatter does not handle it, an instance of ZonedDateTime
can't be formed.
You can also see it in the stacktrace, that contains
Caused by: java.time.DateTimeException: Unable to obtain LocalTime from TemporalAccessor: {},ISO,Europe/Berlin resolved to 2015-11-13 of type java.time.format.Parsed
at java.time.LocalTime.from(LocalTime.java:409)
at java.time.ZonedDateTime.from(ZonedDateTime.java:560)
... 5 more
Depending on what you want, you could build a custom formatter with DateTimeFormatterBuilder
and call parseDefaulting
to provide a default values for each time chrono fields. If you want to default to midnight, you can set NANO_OF_DAY
to 0. A sample example would be
public static void main(String[] args) {
DateTimeFormatter formatter =
new DateTimeFormatterBuilder().appendPattern("yyyyMMdd")
.parseDefaulting(ChronoField.NANO_OF_DAY, 0)
.toFormatter()
.withZone(ZoneId.of("Europe/Berlin"));
OffsetDateTime offsetDateTime = ZonedDateTime.parse("20151113", formatter).toOffsetDateTime();
System.out.println(offsetDateTime.format(DateTimeFormatter.ISO_DATE));
}
Another possible solution would be to parse the text as a LocalDate
and then construct a ZoneDateTime
with it:
public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
LocalDate parsed = LocalDate.parse("20151113", formatter);
ZonedDateTime zonedDateTime = ZonedDateTime.of(parsed, LocalTime.MIDNIGHT, ZoneId.of("Europe/Berlin"));
// get OffsetDateTime similarly
}
The Java 8 java.time.*
package is a very strict package. It doesn't allow flexibility between types and inputs - if you want a ZonedDateTime
object, you must construct it from an input that has a time zone, a date & a time.
If you want to use just a date to construct an object it has to be of a type that doesn't have a time field, specifically, LocalDate
.