241

I am simply trying to convert a date string into a DateTime object in Java 8. Upon running the following lines:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
LocalDateTime dt = LocalDateTime.parse("20140218", formatter);

I get the following error:

Exception in thread "main" java.time.format.DateTimeParseException: 
Text '20140218' could not be parsed: 
Unable to obtain LocalDateTime from TemporalAccessor: 
{},ISO resolved to 2014-02-18 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.LocalDateTime.parse(LocalDateTime.java:492)

The syntax is identical to what has been suggested here, yet I am served with an exception. I am using JDK-8u25.

Community
  • 1
  • 1
retrography
  • 6,302
  • 3
  • 22
  • 32

13 Answers13

251

It turns out Java does not accept a bare Date value as DateTime. Using LocalDate instead of LocalDateTime solves the issue:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
LocalDate dt = LocalDate.parse("20140218", formatter);
retrography
  • 6,302
  • 3
  • 22
  • 32
  • 74
    For what it's worth: I had this same problem even when using `LocalDate` and not `LocalDateTime`. The issue was that I had created my `DateTimeFormatter` using `.withResolverStyle(ResolverStyle.STRICT);`, so I had to use date pattern `uuuuMMdd` instead of `yyyyMMdd` (i.e. "year" instead of "year-of-era")! – ZeroOne Mar 22 '16 at 10:44
  • @ZeroOne's comment should be included as part of the selected answer. – gourabix Jan 08 '21 at 12:56
  • @gourabix I've posted my comment as a separate answer, you may upvote that one. Eventually it will surpass the accepted one in the number of votes... – ZeroOne Jan 08 '21 at 13:03
  • 1
    @iulian-david 's answer was more helpful here and actually solved the problem of parsing a datetime that may or may not have a time part. – cmorris Apr 12 '21 at 23:20
  • "Java does not accept a bare Date value as DateTime"! What a rediculous feature! – Nano Dec 09 '21 at 03:35
  • For those who don't want to convert to localeDate see Julian David answer – Walfrat Mar 16 '22 at 11:26
103

If you really need to transform a date to a LocalDateTime object, you could use the LocalDate.atStartOfDay(). This will give you a LocalDateTime object at the specified date, having the hour, minute and second fields set to 0:

final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
LocalDateTime time = LocalDate.parse("20140218", formatter).atStartOfDay();
Øyvind Mo
  • 1,197
  • 1
  • 8
  • 7
  • 2
    Correction: set to *whatever time it would be at the start of that day*. – Hakanai Jan 04 '16 at 23:27
  • 20
    `LocalDateTime.from` seems unnecessary, as `atStartOfDay()` already returns `LocalDateTime`. – Dariusz Jan 11 '16 at 12:56
  • 2
    scala: val time = LocalDate.parse("20171220", DateTimeFormatter.ofPattern("yyyyMMdd")).atStartOfDay.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) – Woody Sun Dec 20 '17 at 05:09
82

For what is worth if anyone should read again this topic(like me) the correct answer would be in DateTimeFormatter definition, e.g.:

private static DateTimeFormatter DATE_FORMAT =  
            new DateTimeFormatterBuilder().appendPattern("dd/MM/yyyy[ [HH][:mm][:ss][.SSS]]")
            .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
            .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
            .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
            .toFormatter(); 

One should set the optional fields if they will appear. And the rest of code should be exactly the same.

Edit : usefull thing from wittyameta comment :

Remember to add the parseDefaulting AFTER you have called appendPattern. Otherwise it'll give DateTimeParseException

Walfrat
  • 5,363
  • 1
  • 16
  • 35
Iulian David
  • 861
  • 7
  • 6
  • 2
    This is true universal solution for instance for such method: Long getFileTimestamp(String file, Pattern pattern, DateTimeFormatter dtf, int group); Here you have different patterns and DateTimeFormetter, w/ and w/o time specified. – toootooo May 03 '17 at 14:58
  • Can it be a static field? I have not found in the Javadoc that an instance created that way is thread-safe – Kamil Roman Mar 16 '18 at 14:25
  • 1
    Remember to add the `parseDefaulting` AFTER you have called `appendPattern`. Otherwise it'll give `DateTimeParseException`. – wittyameta Nov 15 '18 at 09:04
  • when using ```HH``` for hours in the pattern, i get 00 for AM hours – Panagiss Jan 07 '21 at 16:21
  • If you want to parse fraction of second by JAVA 8, try to visit this log. https://stackoverflow.com/questions/22588051/is-java-time-failing-to-parse-fraction-of-second – jkwli Aug 26 '22 at 08:21
44

For anyone who landed here with this error, like I did:

Unable to obtain LocalDateTime from TemporalAccessor: {HourOfAmPm=0, MinuteOfHour=0}

It came from a the following line:

LocalDateTime.parse(date, DateTimeFormatter.ofPattern("M/d/yy h:mm"));

It turned out that it was because I was using a 12hr Hour pattern on a 0 hour, instead of a 24hr pattern.

Changing the hour to 24hr pattern by using a capital H fixes it:

LocalDateTime.parse(date, DateTimeFormatter.ofPattern("M/d/yy H:mm"));
mawburn
  • 2,232
  • 4
  • 29
  • 48
40

This is a really unclear and unhelpful error message. After much trial and error I found that LocalDateTime will give the above error if you do not attempt to parse a time. By using LocalDate instead, it works without erroring.

This is poorly documented and the related exception is very unhelpful.

Tom B
  • 2,735
  • 2
  • 24
  • 30
37

Expanding on retrography's answer..: I had this same problem even when using LocalDate and not LocalDateTime. The issue was that I had created my DateTimeFormatter using .withResolverStyle(ResolverStyle.STRICT);, so I had to use date pattern uuuuMMdd instead of yyyyMMdd (i.e. "year" instead of "year-of-era")!

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
  .parseStrict()
  .appendPattern("uuuuMMdd")
  .toFormatter()
  .withResolverStyle(ResolverStyle.STRICT);
LocalDate dt = LocalDate.parse("20140218", formatter);

(This solution was originally a comment to retrography's answer, but I was encouraged to post it as a stand-alone answer because it apparently works really well for many people.)

Community
  • 1
  • 1
ZeroOne
  • 3,041
  • 3
  • 31
  • 52
  • 1
    The answer to why "u" instead of "y"has been answered in this link [uuuu-versus-yyyy-in-datetimeformatter-formatting-pattern-codes-in-java](https://stackoverflow.com/questions/41177442/uuuu-versus-yyyy-in-datetimeformatter-formatting-pattern-codes-in-java) @Peru – prashanth Dec 10 '19 at 14:48
18

If the date String does not include any value for hours, minutes and etc you cannot directly convert this to a LocalDateTime. You can only convert it to a LocalDate, because the string only represent the year,month and date components it would be the correct thing to do.

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
LocalDate ld = LocalDate.parse("20180306", dtf); // 2018-03-06

Anyway you can convert this to LocalDateTime.

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
LocalDate ld = LocalDate.parse("20180306", dtf);
LocalDateTime ldt = LocalDateTime.of(ld, LocalTime.of(0,0)); // 2018-03-06T00:00
Ahmed Ashour
  • 5,179
  • 10
  • 35
  • 56
prime
  • 14,464
  • 14
  • 99
  • 131
  • Also make sure the format is correct. This fix didn't work for me until because I set the format to `yyyy-mm-dd` when it should have been `yyyy-MM-dd`. – patstuart Jun 13 '19 at 15:38
5
 DateTimeFormatter format = new DateTimeFormatterBuilder()
                            .appendPattern("yyyy-MM-dd")
                            .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
                            .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
                            .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
                            .parseDefaulting(ChronoField.MILLI_OF_SECOND, 0)
                            .toFormatter();

Works for me

  • for minimum, only `ChronoField.HOUR_OF_DAY` is needed, it does the same thing with the other 3 removed (`MINUTE_OF_HOUR`, `SECOND_OF_MINUTE`, `MILLI_OF_SECOND`) – Mr. Doge Sep 14 '22 at 04:08
5

You do not need to define a DateTimeFormatter

You do not need to define a DateTimeFormatter to parse the given date string. You can use the OOTB (Out-Of-The-Box), DateTimeFormatter.BASIC_ISO_DATE to parse it.

Demo:

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        LocalDate date = LocalDate.parse("20140218", DateTimeFormatter.BASIC_ISO_DATE);
        System.out.println(date);

        // In case you need an instance of LocalDateTime
        LocalDateTime ldt = date.atTime(LocalTime.MIN);
        System.out.println(ldt);
    }
}

Output:

2014-02-18
2014-02-18T00:00

ONLINE DEMO

Learn more about the modern Date-Time API* from Trail: Date Time.


* If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time. Check this answer and this answer to learn how to use java.time API with JDBC.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
3

In cases where you simply want to take a format (whether or not it has time) and want to parse to a LocalDateTime, you can do the following.

LocalDateTime parseDateTime(String dateTime, DateTimeFormatter fmt) {
  return fmt.parse(dateTime, t -> {
    LocalDate date = t.query(TemporalQueries.localDate());
    LocalTime time = t.query(TemporalQueries.localTime());
    return LocalDateTime.of(date, time != null ? time : LocalTime.MIDNIGHT);
  });
}

I needed this because I was getting the date/time pattern as a parameter for a custom Spark UDF.

2

This works fine

public class DateDemo {
    public static void main(String[] args) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy hh:mm");
        String date = "16-08-2018 12:10";
        LocalDate localDate = LocalDate.parse(date, formatter);
        System.out.println("VALUE="+localDate);

        DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
        LocalDateTime parse = LocalDateTime.parse(date, formatter1);
        System.out.println("VALUE1="+parse);
    }
}

output:

VALUE=2018-08-16
VALUE1=2018-08-16T12:10
Jeff Cook
  • 7,956
  • 36
  • 115
  • 186
0

Try this one:

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("MM-dd-yyyy"); 
LocalDate fromLocalDate = LocalDate.parse(fromdstrong textate, dateTimeFormatter);

You can add any format you want. That works for me!

olajide
  • 972
  • 1
  • 13
  • 26
0

I arrived at this problem because my input string didn't have a year in it:

input string: Tuesday, June 8 at 10:00 PM
formatter: DateTimeFormatter.ofPattern("EEEE, MMMM d 'at' h:mm a", Locale.US);

I knew the year so I just appended it to get:

input string: Tuesday, June 8 at 6:30 PM 2021
formatter: DateTimeFormatter.ofPattern("EEEE, MMMM d 'at' h:mm a uuuu", Locale.US);

beefsupreme
  • 125
  • 1
  • 1
  • 9