validationJava 8日期

我想validation几种日期格式,如下例所示:

YYYY YYYY-MM YYYY-MM-DD 

validation必须确保日期格式正确且日期存在。

我知道Java 8提供了一个新的Date API,所以我想知道它是否能够完成这样的工作。

有没有更好的方法使用Java 8 date API? 将Calendar类与lenient参数一起使用仍然是一个好习惯吗?

您可以使用parseDefaulting指定缺少的字段,以使所有格式化程序工作:

 public static boolean isValid(String input) { DateTimeFormatter[] formatters = { new DateTimeFormatterBuilder().appendPattern("yyyy") .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1) .parseDefaulting(ChronoField.DAY_OF_MONTH, 1) .toFormatter(), new DateTimeFormatterBuilder().appendPattern("yyyy-MM") .parseDefaulting(ChronoField.DAY_OF_MONTH, 1) .toFormatter(), new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd") .parseStrict().toFormatter() }; for(DateTimeFormatter formatter : formatters) { try { LocalDate.parse(input, formatter); return true; } catch (DateTimeParseException e) { } } return false; } 

要validationYYYY-MM-DD格式,您可以简单地使用自JDK 8以来在java.time引入的LocalDate.parse

从文本字符串(如2007-12-03)获取LocalDate的实例。

该字符串必须表示有效日期,并使用DateTimeFormatter.ISO_LOCAL_DATE进行解析。

如果日期无效,则抛出DateTimeParseException

对于您给我们的其他两种格式,将抛出exception。 这是合乎逻辑的,因为它们不是真正的约会,只是日期的一部分。


LocalDate还提供了一种方法of(int year, int month, int dayOfMonth)因此,如果你真的想在某些情况下简单地validation年份,在其他情况下的月份或完整日期那么你可以做这样的事情:

 public static final boolean validateInputDate(final String isoDate) { String[] dateProperties = isoDate.split("-"); if(dateProperties != null) { int year = Integer.parseInt(dateProperties[0]); // A valid month by default in the case it is not provided. int month = dateProperties.length > 1 ? Integer.parseInt(dateProperties[1]) : 1; // A valid day by default in the case it is not provided. int day = dateProperties.length > 2 ? Integer.parseInt(dateProperties[2]) : 1; try { LocalDate.of(year, month, day); return true; } catch(DateTimeException e) { return false; } } return false; } 

请注意,您提到了几种格式,但没有提供它们,所以我认为这些只是3种。

使用可选字段和parseBest

您只想validation,我理解,但之后您很可能希望以适当的方式提取数据。 幸运的是,确实如您所写,Java 8提供了这样一种方法parseBest

parseBest适用于可选字段。 因此,首先定义要解析的格式: yyyy[-MM[-dd]] ,括号( [] )包含可选字段。

parseBest还要求您提供几个TemporalQuery 。 实际上,它只是模板方法 R queryFrom(TemporalAccessor)的function包装器。 所以我们实际上可以将TemporalQuery定义为Year::from 。 好的:这正是我们想要的。 问题是parseBest命名并不是很好:它将按顺序解析所有内容并在第一个匹配的TemporalQuery之后停止。 所以在你的情况下,我们必须从最精确到最不精确。 以下是您要处理的各种类型: LocalDateYearMonthYear 。 因此,让我们将TemporalQuery[]定义为LocalDate::from, YearMonth::from, Year::from 。 现在,如果parseBest无法识别您的输入,它将抛出exception。

总而言之,我们将构建parseBest ,如下所示:

 parseBest(DateTimeFormatter.ofPattern("yyyy[-MM[-dd]]"), LocalDate::from, YearMonth::from, Year::from); 

所以让我们正确地写下来:

 static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy[-MM[-dd]]"); static TemporalAccessor parseDate(String dateAsString) { return FORMATTER.parseBest(dateAsString, LocalDate::from, YearMonth::from, Year::from); } 

但是……你只想validation……那么在这种情况下,计算一个日期并且已经完成了昂贵的工作。 所以我们只需将validation定义如下:

 public static boolean isValidDate(String dateAsString) { try { parseDate(dateAsString); return true; } catch (DateTimeParseException e) { return false; } } 

我知道,使用exception来处理这样的情况是不好的,但是当前的API非常强大时,这个非常具体的情况并未考虑在内,所以让我们坚持下去并按原样使用它。

这是完整的代码:

 import java.time.*; import java.time.format.*; import java.time.temporal.*; class Main { private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy[-MM[-dd]]"); static TemporalAccessor parseDate(String dateAsString) { return FORMATTER.parseBest(dateAsString, LocalDate::from, YearMonth::from, Year::from); } public static boolean isValidDate(String dateAsString) { try { parseDate(dateAsString); return true; } catch (DateTimeParseException e) { return false; } } public static void main(String[] args) {  String[] datesAsString = { "2018", "2018-05", "2018-05-22", "abc", "2018-" }; for (String dateAsString: datesAsString) { System.out.printf("%s: %s%n", dateAsString, isValidDate(dateAsString) ? "valid" : "invalid"); } } } 

在线尝试!

输出:

 2018: valid 2018-05: valid 2018-05-22: valid abc: invalid 2018-: invalid 

你想要的不仅仅是validation,比如获得实际价值?

请注意,您仍然可以使用从parseBest检索到的数据进行进一步的使用,如下所示:

 TemporalAccessor dateAccessor = parseDate(dateAsString); if (dateAccessor instanceof Year) { Year year = (Year)dateAccessor; // Use year } else if (dateAccessor instanceof YearMonth) { YearMonth yearMonth = (YearMonth)dateAccessor; // Use yearMonth } else if (dateAccessor instanceof LocalDate) { LocalDate localDate = (LocalDate)dateAccessor; // Use localDate } 
 public static final boolean validateInputDate(final String isoDate, final String dateFormat){ final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat); try { final Date date = simpleDateFormat.parse(isoDate); System.out.println("Date: " + date); return true; } catch (ParseException e) { e.printStackTrace(); return false; } }