I am working on a REST API which supports Date as a query param. Since it is Query param it will be String. Now the Date can be sent in the following formats in the QueryParams:
yyyy-mm-dd[(T| )HH:MM:SS[.fff]][(+|-)NNNN]
It means following are valid dates:
2017-05-05 00:00:00.000+0000
2017-05-05 00:00:00.000
2017-05-05T00:00:00
2017-05-05+0000
2017-05-05
Now to parse all these different date-times i am using Java8 datetime
api. The code is as shown below:
DateTimeFormatter formatter = new DateTimeFormatterBuilder().parseCaseInsensitive()
.append(DateTimeFormatter.ofPattern("yyyy-MM-dd[[ ][['T'][ ]HH:mm:ss[.SSS]][Z]"))
.toFormatter();
LocalDateTime localDateTime = null;
LocalDate localDate = null;
ZoneId zoneId = ZoneId.of(ZoneOffset.UTC.getId());
Date date = null;
try {
localDateTime = LocalDateTime.parse(datetime, formatter);
date = Date.from(localDateTime.atZone(zoneId).toInstant());
} catch (Exception exception) {
System.out.println("Inside Excpetion");
localDate = LocalDate.parse(datetime, formatter);
date = Date.from(localDate.atStartOfDay(zoneId).toInstant());
}
As can be seens from the code I am using DateTimeFormatter
and appending a pattern. Now I am first trying to parse date as LocalDateTime
in the try-block
and if it throws an exception for cases like 2017-05-05
as no time is passed, I am using a LocalDate
in the catch block
.
The above approach is giving me the solution I am looking for but my questions are that is this the standard way to deal with date sent as String and is my approach is in line with those standards?
Also, If possible what is the other way I can parse the different kinds of date (shown as the Valid dates above) except some other straightforward solutions like using an Array list and putting all the possible formats and then using for-loop trying to parse the date?
The output from this snippet is:
The tricks I am using include:
optionalStart
/optionalEnd
or in[]
in a pattern. I use both, each where I find it easier to read, and you may prefer differently.DateTimeFormatter.ISO_LOCAL_TIME
already handles optional seconds and fraction of second.OffsetDateTime
to work we need to supply default values for the parts that may be missing in the query parameter.parseDefaulting
does this.In your code you are converting to a
Date
. Thejava.util.Date
class is long outdated and has a number of design problems, so avoid it if you can.Instant
will do fine. If you do need aDate
for a legacy API that you cannot change or don’t want to change just now, convert in the same way as you do in the question.EDIT: Now defaulting
HOUR_OF_DAY
, notMILLI_OF_DAY
. The latter caused a conflict when only the millis were missing, but it seems the formatter is happy with just default hour of day when the time is missing.I usually use the DateUtils.parseDate which belongs to commons-lang.
This method looks like this:
Here is the description: