Java 8 Time API: how to parse string of format "MM.yyyy" to LocalDate

26,509

Solution 1

It makes sense: your input is not really a date because it does not have a day information. You should parse it as a YearMonth and use that result if you don't care about the day.

String date = "04.2013";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM.yyyy");
YearMonth ym = YearMonth.parse(date, formatter);

If you do need to apply a specific day, you can obtain a LocalDate from a YearMonth for example:

LocalDate ld = ym.atDay(1);
//or
LocalDate ld = ym.atEndOfMonth();

You can also use a TemporalAdjuster, for example, for the last day of the month*:

LocalDate ld = ym.atDay(1).with(lastDayOfMonth());

*with an import static java.time.temporal.TemporalAdjusters.lastDayOfMonth;

Solution 2

Following alternative is probably not so nice but at least a successfully tested solution, too, so I mention it here for completeness and as supplement to the right answer of @assylias:

DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
builder.parseDefaulting(ChronoField.DAY_OF_MONTH, 1);
builder.append(DateTimeFormatter.ofPattern("MM.yyyy"));
DateTimeFormatter dtf = builder.toFormatter();

String ym = "04.2013";
LocalDate date = LocalDate.parse(ym, dtf);
System.out.println(date); // output: 2013-04-01
Share:
26,509
Maxim Kolesnikov
Author by

Maxim Kolesnikov

One direction time traveler

Updated on July 21, 2022

Comments

  • Maxim Kolesnikov
    Maxim Kolesnikov almost 2 years

    I'm a bit discouraged with parsing dates in Java 8 Time API.

    Previously I could easily write:

    String date = "04.2013";
    DateFormat df = new SimpleDateFormat("MM.yyyy");
    Date d = df.parse(date);
    

    But now if I use LocalDate and do it like this:

    String date = "04.2013";
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM.yyyy");
    LocalDate ld = LocalDate.parse(date, formatter);
    

    I receive an exception:

    java.time.format.DateTimeParseException: Text '04' could not be parsed at index 0
    java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1948)
    java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1850)
    java.time.LocalDate.parse(LocalDate.java:400)
    java.time.LocalDate.parse(LocalDate.java:385)
    com.luxoft.ath.controllers.JsonController.region(JsonController.java:38)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:483)
    org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
    org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689)
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:723)
    org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    

    If I change string format to "yyyy-MM-dd" everything work perfectly, even without formatter:

    String date = "2013-04-12";
    LocalDate ld = LocalDate.parse(date);
    

    So my question is: how to parse date in custom format using Java 8 Time API?

  • ADTC
    ADTC about 10 years
    That makes sense. If you are only representing a year and month (the exact date is irrelevant), then you only need to work with YearMonth. You don't need to convert it to LocalDate unlike pre-Java8 where we had to convert it to a default date of 1. :)
  • ADTC
    ADTC about 10 years
    You can do LocalDate ld = ym.atEndOfMonth(); too.. Seriously, Java 8 Time API (JodaTime) is amazing :)