Reputation: 266
I have a certain class that parses a (fairly) wide variety of dates:
// imports omitted for brevity
public final class DateParser
{
private static final String DATE_TIME_FORMAT_PATTERN
= "[h][hh][[:][.]mm][[ ]a][ v][ ][[EEEE ][E ][d][dd][/][-][LLLL][L][/][-][uuuu]]";
private static final DateTimeFormatter formatter
= DateTimeFormatter.ofPattern(DATE_TIME_FORMAT_PATTERN).localizedBy(Locale.ENGLISH);
public static ZonedDateTime parseDateTimeString(final String dateTimeString)
{
TemporalAccessor parsedString = formatter.parse(dateTimeString);
ZonedDateTime returnable = ZonedDateTime.now();
// Return a ZonedDateTime with sane defaults if some fields are missing from parsedString
}
}
I would like to return a ZonedDateTime
that has sane defaults if parsedString is not a complete ZonedDateTime
.
Say, for instance, that the string given to the method is "5:45pm"
(which will parse successfully); I would like the ZonedDateTime to reflect 5:45 pm today, at the current time zone. Of course, a more pre-emptive way would be to reflect 5:45pm the next day if it is already past quarter to six today, but I'd like to get this implemented first.
Other possible inputs are just the day of week, for instance, "Monday"
: this would return a ZonedDateTime
set for the next Monday after the current day, at 12 pm, at the local time zone.
An input of just a date "4/2/2020"
would return a ZonedDateTime
set at the local time zone, the date in the input (the 4th of February, 2020), with time set at 12 pm.
How would I go about doing this? I currently have bit of code, that just consists of a very long chain of if
s:
if (parsedString.isSupported(ChronoField.YEAR))
{
returnable = returnable.withYear(parsedString.get(ChronoField.YEAR));
}
if (parsedString.isSupported(ChronoField.DAY_OF_MONTH))
{
returnable = returnable.withMonth(parsedString.get(ChronoField.MONTH_OF_YEAR));
}
if (parsedString.isSupported(ChronoField.DAY_OF_MONTH))
{
returnable = returnable.withDayOfMonth(parsedString.get(ChronoField.DAY_OF_MONTH));
}
// And so on.
However, this merely modifies the current date-time group. I am not sure how to implement things like (2) and (3).
Furthermore, it possible to build up a ZonedDateTime
from parsedString
, by iterating over its fields, somehow? Or is there some other way to achieve this entire parsing idea?
Thanks, everyone.
Upvotes: 0
Views: 188
Reputation: 44404
I don’t think you can do this with only a pattern, but you can create a DateTimeFormatterBuilder and call its parseDefaulting method:
DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
builder.appendPattern(DATE_TIME_FORMAT_PATTERN);
ZonedDateTime defaults = ZonedDateTime.now();
builder.parseDefaulting(ChronoField.YEAR,
defaults.getLong(ChronoField.YEAR));
builder.parseDefaulting(ChronoField.MONTH_OF_YEAR,
defaults.getLong(ChronoField.MONTH_OF_YEAR));
builder.parseDefaulting(ChronoField.DAY_OF_MONTH,
defaults.getLong(ChronoField.DAY_OF_MONTH));
// etc.
DateTimeFormatter formatter = builder.toFormatter();
ZonedDateTime returnable = ZonedDateTime.parse(dateTimeString, formatter);
Upvotes: 1