Когда я сталкиваюсь с недопустимыми датами, например 2018-02-31, 2018-11-31, я хочу, чтобы мой код преобразовал их в последний день этого месяца.
Я не уверен, как проверить значение в переданной строке.
Вот мой код:
/**
* If date comes back as invalid, i.e. 2018-11-31
* convert it to have last day of given month.
*
* @param nextFieldTypeDate
* @return
*/
public static LocalDate resolveInvalidDate(String nextFieldTypeDate) {
LocalDate convertedDate = null;
try {
convertedDate = LocalDate.parse(nextFieldTypeDate);
} catch(DateTimeException dte) {
//convertedDate = convert date to have last day of the month
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM");
String yearMonthString = nextFieldTypeDate.subSequence(0, 7).toString();
YearMonth ym = YearMonth.parse(yearMonthString, fmt);
convertedDate = ym.atEndOfMonth();
} catch(Exception e) {
logger.error(e.getMessage());
throw new ConversionException("Unable to convert nextFieldTypeDate.", e);
}
return convertedDate;
}




Метод parseUnresolved в DatetimeFormatter выполняет синтаксический анализ, не пытаясь понять анализируемые значения. Поэтому он принимает недопустимую дату и позволяет вам проверить проанализированные значения, прежде чем вы попытаетесь сделать из них LocalDate.
public static LocalDate resolveInvalidDate(String nextFieldTypeDate) {
ParsePosition position = new ParsePosition(0);
TemporalAccessor parsed = DateTimeFormatter.ISO_LOCAL_DATE
.parseUnresolved(nextFieldTypeDate, position);
if (position.getIndex() < nextFieldTypeDate.length()) {
throw new IllegalArgumentException("Could not parse entire string");
}
YearMonth ym = YearMonth.from(parsed);
int lastDayOfMonth = ym.lengthOfMonth();
int parsedDayOfMOnth = parsed.get(ChronoField.DAY_OF_MONTH);
if (parsedDayOfMOnth > lastDayOfMonth) { // invalid, must be adjusted to lasst day of month
return ym.atEndOfMonth();
} else {
return ym.atDay(parsedDayOfMOnth);
}
}
Давайте попробуем эту версию вашего метода:
System.out.println(resolveInvalidDate("2018-02-31"));
System.out.println(resolveInvalidDate("2018-02-27"));
Выход:
2018-02-28 2018-02-27
Таким образом, 31 февраля было недействительным и было изменено на 28 февраля, которое в 2018 году было последним днем этого месяца. 27 февраля действительно и возвращается как есть.
Редактировать: Для связанных целей можно было бы рассмотреть намного более простой DateTimeFormatter.ISO_LOCAL_DATE.withResolverStyle(ResolverStyle.LENIENT).parse(nextFieldTypeDate, LocalDate::from). Это, однако, превращает 2018-02-31 в 2018-03-03, что, как я понимаю, не то, что вам нужно.
Оно делает. Вы хотите, чтобы 14 было уменьшено до 12? Вы можете добавить это к своему вопросу.
Нет. Я поместил его в try-catch и генерирую исключение, если указан недопустимый месяц.
Не самое чистое решение, но оно должно работать:
public static LocalDate resolveInvalidDate(String nextFieldTypeDate) {
LocalDate convertedDate = null;
try {
convertedDate = LocalDate.parse(nextFieldTypeDate);
} catch(DateTimeException dte) {
//convertedDate = convert date to have last day of the month
Integer[] constituents = Arrays.stream(nextFieldTypeDate.split("-"))
.map(constituentString -> Integer.valueOf(constituentString))
.toArray(Integer::new);
LocalDate defaultDate = LocalDate.of(constituents[0], constituents[1], 1);
LocalDate convertedDate = LocalDate.of(defaultDate.getYear(), defaultDate.getMonth(), defaultDate.lengthOfMonth());
} catch(Exception e) {
logger.error(e.getMessage());
throw new ConversionException("Unable to convert nextFieldTypeDate.", e);
}
return convertedDate;
}
когда я прохожу 2018-14-25, он взрывается на YearMonth ym = YearMonth.from (разобранный);