Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsing date and AM/PM using java 8 DateTime API

I'm trying to parse a date time string using java 8 DateTime API.

The string to parse contains date, month, year and AM/PM marker such as 17/02/2015 PM. I use the following pattern: dd/MM/yyyy aa and I expect the parsed LocalDateTime time part to be set at 12:00:00 or 00:00:00 depending on the AM/PM marker.

Using the former java.text.SimpleDateFormat API, the parsing works as expected using this pattern.

But when i use java 8 DateTime API and run the following code:

LocalDateTime.parse("17/02/2015 PM", DateTimeFormatter.ofPattern("dd/MM/yyyy aa"));

I got the following exception:

Exception in thread "main" java.lang.IllegalArgumentException: Too many pattern letters: a
at java.time.format.DateTimeFormatterBuilder.parseField(DateTimeFormatterBuilder.java:1765)
at java.time.format.DateTimeFormatterBuilder.parsePattern(DateTimeFormatterBuilder.java:1604)
at java.time.format.DateTimeFormatterBuilder.appendPattern(DateTimeFormatterBuilder.java:1572)
at java.time.format.DateTimeFormatter.ofPattern(DateTimeFormatter.java:534)

If i switch the pattern to dd/MM/yyyy a then i got the folowing exception:

Exception in thread "main" java.time.format.DateTimeParseException: Text '17/02/2015 PM' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {AmPmOfDay=1},ISO resolved to 2015-02-17 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)
Caused by: java.time.DateTimeException: Unable to obtain LocalDateTime from TemporalAccessor: {AmPmOfDay=1},ISO resolved to 2015-02-17 of type java.time.format.Parsed
    at java.time.LocalDateTime.from(LocalDateTime.java:461)
    at java.time.LocalDateTime$$Lambda$7/474675244.queryFrom(Unknown Source)
    at java.time.format.Parsed.query(Parsed.java:226)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1849)
    ... 2 more
Caused by: java.time.DateTimeException: Unable to obtain LocalTime from TemporalAccessor: {AmPmOfDay=1},ISO resolved to 2015-02-17 of type java.time.format.Parsed
    at java.time.LocalTime.from(LocalTime.java:409)
    at java.time.LocalDateTime.from(LocalDateTime.java:457)
    ... 5 more

It's also weird that when i do the reverse operation, format, it works fine:

 System.out.println(LocalDateTime.of(2015, 02, 17, 0, 0, 0).format(DateTimeFormatter.ofPattern("dd/MM/yyyy a")));
 System.out.println(LocalDateTime.of(2015, 02, 17, 12, 0, 0).format(DateTimeFormatter.ofPattern("dd/MM/yyyy a")));

respectively prints 17/02/2015 AM and 17/02/2015 PM.

The javadoc for java.time.DateTimeFormatter says (§Resolving, step #6):

  1. A LocalTime is formed if there is at least an hour-of-day available. This involves providing default values for minute, second and fraction of second.

What i understand is that the field hour-of-day is mandatory to parse a LocalDateTime... Isn't there any way to parse the time part only using the AM/PM field only?

like image 467
Benjamin Avatar asked Aug 24 '15 10:08

Benjamin


People also ask

How do I format a date in Java 8?

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); System. out. println(sdf. parse(dtf.

Which time format is followed in Java 8?

Java 8 provides ZonedDateTime when we need to deal with time-zone-specific date and time. The ZoneId is an identifier used to represent different zones. There are about 40 different time zones, and the ZoneId represents them as follows. Another way to work with time zone is by using OffsetDateTime.

What is the default format of LocalTime in Java 8?

LocalTime is an immutable class whose instance represents a time in the human readable format. It's default format is hh:mm:ss. zzz.


1 Answers

You can set the default values for unavailable fields via DateTimeFormatterBuilder.parseDefaulting:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    .appendPattern("dd/MM/yyyy a")
    .parseDefaulting(ChronoField.HOUR_OF_AMPM, 0) // this is required
    .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0) // optional, but you can set other value
    .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0) // optional as well
    .toFormatter();
System.out.println(LocalDateTime.parse("17/02/2015 PM", formatter)); // 2015-02-17T12:00
System.out.println(LocalDateTime.parse("17/02/2015 AM", formatter)); // 2015-02-17T00:00
like image 77
Tagir Valeev Avatar answered Oct 03 '22 07:10

Tagir Valeev