Antonio Antonio - 1 month ago 13
Java Question

Java 8 parse ZonedDateTime from string not containing all fields

When I have only year (and possibly several other temporal fields) specified in a string pattern, I would like the other absent fields to be set to their lowest values. For example, prior to Java 8 my code looked like

String source = "2015";
String pattern = "yyyy";
DateFormat sdf = new SimpleDateFormat(pattern);
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = null;
try {
date = sdf.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}

SimpleDateFormat sdfGMT2 = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss z");
sdfGMT2.setTimeZone(TimeZone.getTimeZone("GMT"));

String newf = sdfGMT2.format(date);
System.out.println(newf);


which returns me
2015.01.01 00:00:00 GMT


However, in
java.time
formatter returns a
TemporalAccessor
; the code below throws exception

DateTimeFormatter fmt = DateTimeFormatter.ofPattern("YYYY");
ZonedDateTime zonedDateTime = ZonedDateTime.parse("2008", fmt);


Exception:


java.time.format.DateTimeParseException: Text '2008' could not be parsed: Unable to obtain
ZonedDateTime from TemporalAccessor: {WeekBasedYear[WeekFields[SUNDAY,1]]=2008},ISO
of type java.time.format.Parsed


How do I achieve the same result with Java 8 time API as I did with older API?

Answer

It's a bit more verbose, but you have to specify the default values for missing fields when creating your DateTimeFormatter:

DateTimeFormatter fmt = new DateTimeFormatterBuilder()
        .appendValue(ChronoField.YEAR)
        .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
        .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
        .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
        .toFormatter()
        .withZone(ZoneOffset.UTC);

ZonedDateTime zonedDateTime = ZonedDateTime.parse("2008", fmt);

This includes the ZoneId which is necessary for a ZonedDateTime.