Unable to obtain ZonedDateTime from TemporalAccessor using DateTimeFormatter and ZonedDateTime in Java 8

StackOverflow https://stackoverflow.com/questions/23596530

문제

I recently moved to Java 8 to, hopefully, deal with local and zoned times more easily.

However, I'm facing an, in my opinion, simple problem when parsing a simple date.

public static ZonedDateTime convertirAFecha(String fecha) throws Exception {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
            ConstantesFechas.FORMATO_DIA).withZone(
            obtenerZonaHorariaServidor());

    ZonedDateTime resultado = ZonedDateTime.parse(fecha, formatter);
    return resultado;
}

In my case:

  • fecha is '15/06/2014'
  • ConstantesFechas.FORMATO_DIA is 'dd/MM/yyyy'
  • obtenerZonaHorariaServidor returns ZoneId.systemDefault()

So, this is a simple example. However, the parse throws this exception:

java.time.format.DateTimeParseException: Text '15/06/2014' could not be parsed: Unable to obtain ZonedDateTime from TemporalAccessor: {},ISO resolved to 2014-06-15 of type java.time.format.Parsed

Any tips? I've been trying different combinations of parsing and using TemporalAccesor, but without any luck so far.

도움이 되었습니까?

해결책

This does not work because your input (and your Formatter) do not have time zone information. A simple way is to parse your date as a LocalDate first (without time or time zone information) then create a ZonedDateTime:

public static ZonedDateTime convertirAFecha(String fecha) {
  DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
  LocalDate date = LocalDate.parse(fecha, formatter);

  ZonedDateTime resultado = date.atStartOfDay(ZoneId.systemDefault());
  return resultado;
}

다른 팁

This is a bug, see JDK-bug-log. According to that information the problem was solved for Java 9 and Java 8u20. Try to download the latest Java 8 - version. Today on 2014-05-12: There is an early access release 8u20 available.

UPDATE:

Personally I think, since you only have and expect "dd/MM/yyyy" as pattern you should use LocalDate as your primary type as @assylias has already proposed. Regarding your context, it is almost sure a design failure to use ZonedDateTime. What do you want to do with objects of this type? I can only think of specialized timezone calculations as use-case. And you cannot even directly store these ZonedDateTime-objects in a database, so this type is far less useful than many people believe.

What I described as your use-case problem is indeed a new aspect introduced with Java-8 compared with the old GregorianCalendar-class (which is an all-in-one-type). Users have to start thinking about choosing the proper temporal type for their problems and use-cases.

In simple words, the line

ZonedDateTime.parse('2014-04-23', DateTimeFormatter.ISO_OFFSET_DATE_TIME)

throws an exception:

Text '2014-04-23' could not be parsed at index 10
java.time.format.DateTimeParseException: Text '2014-04-23' could not be parsed at index 10

It looks like a bug for me.

I used this workaround:

String dateAsStr = '2014-04-23';
if (dateAsStr.length() == 10) {
    dateAsStr += 'T00:00:00';
}
ZonedDateTime.parse(dateAsStr, DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(ZoneId.systemDefault()));

If coming from Google:

Instead of doing:

ZonedDateTime.from(new Date().toInstant());

Try this:

ZonedDateTime.ofInstant(new Date(), ZoneId.of("UTC")); 

Just an example conversions, I believe some folks will get the exception below

(java.time.DateTimeException: Unable to obtain LocalDateTime from TemporalAccessor: 2014-10-24T18:22:09.800Z of type java.time.Instant)

if they try

LocalDateTime localDateTime = LocalDateTime.from(new Date().toInstant());

to resolve the issue, please pass in Zone -

LocalDateTime localDateTime = LocalDateTime.from(new Date()
        .toInstant().atZone(ZoneId.of("UTC")));
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top