10

Basically I have a field

private LocalDateTime date;

which is parsed from String. It works fine when provided String has time appended at the end but will throw an exception if it has not.

DateTimeFormatter formatter = null;
if (value.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}")) {
    formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
} else if (value.matches("\\d{4}-\\d{2}-\\d{2}")) {
    formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
}
// Throws an exception for pattern "yyyy-MM-dd"
date = LocalDateTime.parse(value, formatter);

And the exception itself:

java.time.format.DateTimeParseException: Text '2000-06-29' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {},ISO resolved to 2000-06-29 of type java.time.format.Parsed
at pl.empirica.swissborg.service.util.CsvBeanUtils.copyList(CsvBeanUtils.java:75) ~[classes/:na]
at pl.empirica.swissborg.service.csv.CsvReaderService.persistCsvData(CsvReaderService.java:101) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_91]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_91]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_91]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_91]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:354) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:305) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:133) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
... 18 common frames omitted
Caused by: java.lang.RuntimeException: java.time.format.DateTimeParseException: Text '2000-06-29' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {},ISO resolved to 2000-06-29 of type java.time.format.Parsed
at pl.empirica.swissborg.service.util.CsvBeanUtils.copyFields(CsvBeanUtils.java:58) ~[classes/:na]
at pl.empirica.swissborg.service.util.CsvBeanUtils.copyList(CsvBeanUtils.java:70) ~[classes/:na]
... 26 common frames omitted
Caused by: java.time.format.DateTimeParseException: Text '2000-06-29' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {},ISO resolved to 2000-06-29 of type java.time.format.Parsed
at java.time.format.DateTimeFormatter.createError(Unknown Source) ~[na:1.8.0_91]
at java.time.format.DateTimeFormatter.parse(Unknown Source) ~[na:1.8.0_91]
at java.time.LocalDateTime.parse(Unknown Source) ~[na:1.8.0_91]
at pl.empirica.swissborg.service.util.CsvBeanUtils.copyFields(CsvBeanUtils.java:47) ~[classes/:na]
... 27 common frames omitted
Caused by: java.time.DateTimeException: Unable to obtain LocalDateTime from TemporalAccessor: {},ISO resolved to 2000-06-29 of type java.time.format.Parsed
at java.time.LocalDateTime.from(Unknown Source) ~[na:1.8.0_91]
at java.time.format.Parsed.query(Unknown Source) ~[na:1.8.0_91]
... 30 common frames omitted
Caused by: java.time.DateTimeException: Unable to obtain LocalTime from TemporalAccessor: {},ISO resolved to 2000-06-29 of type java.time.format.Parsed
at java.time.LocalTime.from(Unknown Source) ~[na:1.8.0_91]
... 32 common frames omitted

EDIT: for clarification, I'm 100% certain that formatter is set by the 2nd conditional branch.

Arqan
  • 376
  • 1
  • 3
  • 14
  • Check if `formatter` is not null. It might not went through your if statement – Vygintas B Oct 21 '16 at 11:23
  • you should try parsing that to LocalDate. LocalDate date = LocalDate.parse(value, formatter) for date only pattern. If you really want to LocalDateTime then you should parse to Local Date and set the time by using atStartOfDay(). – s7vr Oct 21 '16 at 11:26
  • As Veeram says, LocalDateTime is expecting a time to be set. It will try to parse it, but can't find it. Use LocalDate or check the answer of @assylias – Wesley De Keirsmaeker Oct 21 '16 at 11:32
  • Actually you will get problem when you will try to parse "yyyy-MM-dd" to LocalDateTime – newuserua_ext Oct 21 '16 at 11:39

1 Answers1

30

Your issue is that a LocalDateTime needs a time!

You have two main options:

  • use two formatters like you do, but the second branch should be LocalDateTime d = LocalDate.parse(value, formatter).atStartOfDay() (for example)
  • create a formatter that can handle both formats

The second option could look like:

DateTimeFormatter fmt = new DateTimeFormatterBuilder()
        .appendPattern("yyyy-MM-dd")
        .optionalStart()
        .appendPattern(" HH:mm")
        .optionalEnd()
        .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
        .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
        .toFormatter();

which can parse 2016-10-01 and 2016-10-01 10:15.

assylias
  • 321,522
  • 82
  • 660
  • 783
  • 4
    That second one is awesome. Basically does exactly what question requests using standard tools. I can't get over this thing with Java having respectable Date/Time machinery. – SusanW Oct 21 '16 at 11:37
  • http://stackoverflow.com/questions/27454025/unable-to-obtain-localdatetime-from-temporalaccessor-when-parsing-localdatetime look at this.possible duplicate. – Zia Oct 21 '16 at 11:39
  • 2
    @Arqan A `LocalDateTime` is definitively "a local date and time". If you don't want have the time specified, you _have_ to use something else (eg `LocalDate`, as per option 1). Otherwise it's like saying "can I have an int but without all that number stuff?" :-) – SusanW Oct 21 '16 at 11:41
  • 2
    @Arqan You could split the date and time components into a LocalDate and a LocalTime and keep the LocalTime null when there is no time. It really depends on what you are trying to achieve. – assylias Oct 21 '16 at 11:54
  • 1
    I think since it lets you specify a pattern without a time, it should be capable of parsing that pattern (but it's not capable, java has made this unintuitive). LocalDate.parse() takes a DateTimeFormatter, just like LocalDateTime.parse() does. Another point is that OffsetDateTime.parse() will work without a time, though you have to specify the zone / offset. – Ben Horner Nov 15 '18 at 21:12