Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to determine if a DateTimeFormatter is date only or time only after construction?

With Java 8's new date time library, the way to parse strings into dates is to use the DateTimeFormatter. LocalDate, LocalTime and LocalDateTime all have a static parse method that takes in a String and a formatter. A potential gotcha is that if your DateTimeFormat does not contain a time portion (or for DateTime, a date portion) you end up getting a parse error even if your pattern matches.

Example

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("YYYY-MM-DD");
LocalDateTime dt = LocalDateTime.parse("2016-01-11", formatter);

This will throw a DateTimeParseException (as discussed here) with the message

java.time.format.DateTimeParseException:
Text '2016-01-11' could not be parsed:
Unable to obtain LocalDateTime from TemporalAccessor

This is a somewhat unhelpful error message as the text can be parsed since it matches the pattern. Rather the error has to do with the fact that it cannot create the time portion of LocalDateTime. Refactoring the code to the below works:

LocalDateTime ldt = LocalDate.parse("2016-01-11", formatter).atStartOfDay());

My question is, say you had a generic method like such

 public static LocalDateTime getDate(String s, DateTimeFormatter format) {
  ...
  }

Is there a way to determine which static parse method you would need to call to coerce the string into a LocalDateTime by applying some default logic? e.g. If date only use midnight, if time only use today, etc.

like image 730
joecoder Avatar asked Jan 14 '16 15:01

joecoder


People also ask

How do I use DateTimeFormatter with date?

DateTimeFormatter fmt = DateTimeFormatter. ofPattern("yyyy-MM-dd'T'HH:mm:ss"); System. out. println(ldt.

What is the difference between DateTimeFormatter and SimpleDateFormat?

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

Is Java time DateTimeFormatter thread-safe?

A formatter created from a pattern can be used as many times as necessary, it is immutable and is thread-safe. The count of pattern letters determines the format.

What is the Java time format DateTimeFormatter?

format. DateTimeFormatterBuilder Class in Java. DateTimeFormatterBuilder Class is a builder class that is used to create date-time formatters. DateTimeFormatter is used as a Formatter for printing and parsing date-time objects.


1 Answers

I think you have the question in reverse. You don't want to determine if a formatter uses only a date or a date/time. You create a formatter based on what you should parse and on what you intend to store the result to. Obviously, if you create a formatter that does not handle the time part, using it to parse into a LocalDateTime is a misconception.

If you need to parse dates that can arrive with two formats like "yyyy-MM-dd" or "yyyy-MM-dd HH:mm:ss" (with a time part), it is not up to the parsing to determine what it should do but up to the formatter to provide defaults in the case that there is no time.

With Java Time, this is done with optional sections and default values. For example, the pattern "yyyy-MM-dd[ HH:mm:ss]" will be able to parse date String (like "2016-01-11") and date/time String (like "2016-01-11 20:10:10"). If you will store that into a LocalDateTime, you will need to provide default values in case there is no time component. This is done with parseDefaulting(field, value): this will tell the formatter to return the given default value for that chrono field if it was not already set.

The following code creates such a formatter and defaults the time part to midnight.

public static void main(String[] args) {
    DateTimeFormatter formatter = 
            new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd[ HH:mm:ss]")
                                          .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
                                          .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
                                          .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
                                          .toFormatter();

    LocalDateTime dt1 = LocalDateTime.parse("2016-01-11", formatter);
    LocalDateTime dt2 = LocalDateTime.parse("2016-01-11 20:10:10", formatter);
}

This logic could of course be extended to parse time only String and defaulting the date component to the current date.

like image 62
Tunaki Avatar answered Sep 19 '22 10:09

Tunaki