Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between parse() of DateFormat and SimpleDateFormat

Tags:

java

java-8

I am trying to parse the date using LocalDateTime.parse the method however I am getting below error. the date string is getting parse if I use SimpleDateFormat simple date format object.

Has anyone faced this issue! What's the difference between parse from DateFormat and LocalDateTime

package com.example.demo;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;

public class App {

    public static final String DATE_TIME_PATTERN = "dd-MM-yyyy hh:mm:ss.SSS";

    public static final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat(DATE_TIME_PATTERN);

    public static final String SEPERATOR = ",";

    public static void main(String[] args) {
        try {
            Date date = DATE_TIME_FORMAT.parse("12-03-2019 10:28:50.013");
            System.out.println("date : {} " + date);

            LocalDateTime startTimestamp = LocalDateTime.parse("12-03-2019 10:28:50.013", DateTimeFormatter.ofPattern(DATE_TIME_PATTERN)).plusNanos(1000000);
            System.out.println("startTimestamp : {} " + startTimestamp);
        } catch(Exception e) {
            e.printStackTrace();
        }

    }

}

OUTPUT

date : {} Tue Mar 12 10:28:50 SGT 2019
java.time.format.DateTimeParseException: Text '12-03-2019 10:28:50.013' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {NanoOfSecond=13000000, HourOfAmPm=10, MicroOfSecond=13000, SecondOfMinute=50, MilliOfSecond=13, MinuteOfHour=28},ISO resolved to 2019-03-12 of type java.time.format.Parsed
    at java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:1920)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1855)
    at java.time.LocalDateTime.parse(LocalDateTime.java:492)
    at com.example.demo.App.main(App.java:21)
Caused by: java.time.DateTimeException: Unable to obtain LocalDateTime from TemporalAccessor: {NanoOfSecond=13000000, HourOfAmPm=10, MicroOfSecond=13000, SecondOfMinute=50, MilliOfSecond=13, MinuteOfHour=28},ISO resolved to 2019-03-12 of type java.time.format.Parsed
    at java.time.LocalDateTime.from(LocalDateTime.java:461)
    at java.time.format.Parsed.query(Parsed.java:226)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
    ... 2 more
Caused by: java.time.DateTimeException: Unable to obtain LocalTime from TemporalAccessor: {NanoOfSecond=13000000, HourOfAmPm=10, MicroOfSecond=13000, SecondOfMinute=50, MilliOfSecond=13, MinuteOfHour=28},ISO resolved to 2019-03-12 of type java.time.format.Parsed
    at java.time.LocalTime.from(LocalTime.java:409)
    at java.time.LocalDateTime.from(LocalDateTime.java:457)
    ... 4 more
like image 902
Jigar Naik Avatar asked Mar 12 '19 03:03

Jigar Naik


People also ask

What is the difference between DateFormat and SimpleDateFormat?

The java SimpleDateFormat allows construction of arbitrary non-localized formats. The java DateFormat allows construction of three localized formats each for dates and times, via its factory methods.

What does SimpleDateFormat parse do?

SimpleDateFormat is a concrete class for formatting and parsing dates in a locale-sensitive manner. It allows for formatting (date -> text), parsing (text -> date), and normalization. SimpleDateFormat allows you to start by choosing any user-defined patterns for date-time formatting.

What is the difference between DateTimeFormatter and SimpleDateFormat?

DateTimeFormatter is a replacement for the old SimpleDateFormat that is thread-safe and provides additional functionality.

What does SimpleDateFormat return?

SimpleDateFormat format() Method in Java with Examples Return Value: The method returns Date or time in string format of mm/dd/yyyy.


1 Answers

You are using the clock-hour-of-am-pm (1-12) for hour which is h in your pattern and not hour-of-day (0-23) which is H, so it needs the additional info of the AM/PM.

enter image description here

So ideally the AM/PM must be mentioned in the date string which is to be parsed along with a for am-pm-of-day which also needs to be added in the DATE_TIME_PATTERN String.

public static final String DATE_TIME_PATTERN = "dd-MM-yyyy hh:mm:ss.SSS a";

public static final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat(DATE_TIME_PATTERN);

  public static final String SEPERATOR = ",";

    public static void main(String[] args) {
        try {
            Date date = DATE_TIME_FORMAT.parse("12-03-2019 10:28:50.013 AM");
            System.out.println("date : {} " + date);

            LocalDateTime startTimestamp = LocalDateTime.parse("12-03-2019 10:28:50.013 AM", DateTimeFormatter.ofPattern(DATE_TIME_PATTERN)).plusNanos(1000000);
            System.out.println("startTimestamp : {} " + startTimestamp);
        } catch(Exception e) {
            e.printStackTrace();
        }

    }

Output:

date : {} Tue Mar 12 10:28:50 IST 2019
startTimestamp : {} 2019-03-12T10:28:50.014

We can see that without the proper format SimpleDateFormat is working while LocalDateTime is more stricter when it comes to parsing invalid date strings. In your case since the required AM/PM info is missing, the LocalTime returned from the TemporalAccessor is null and hence you are getting Unable to obtain LocalTime from TemporalAccessor.

No coming to why SimpleDateFormat is working, there is a method called setLenient(boolean lenient) if you pass hour which is greater than 12 without mentioning a in the pattern and AM/PM in the date string an java.text.ParseException: Unparseable date: will be thrown.

But since in your case you are passing the hour as 10 this is less than 12 and hence it is interpreted as AM by default.

This is the code in SimpleDateFormat class where this checking is happening:

case PATTERN_HOUR1: // 'h' 1-based.  eg, 11PM + 1 hour =>> 12 AM
     if (!isLenient()) {
         // Validate the hour value in non-lenient
         if (value < 1 || value > 12) {
             break parsing;
         }
     }
     // [We computed 'value' above.]
     if (value == calendar.getLeastMaximum(Calendar.HOUR) + 1) {
         value = 0;
     }
     calb.set(Calendar.HOUR, value);
     return pos.index;
like image 100
Fullstack Guy Avatar answered Oct 28 '22 16:10

Fullstack Guy