验证Java8日期
我想验证几种日期格式,如下示例:验证Java8日期,java,java-8,Java,Java 8,我想验证几种日期格式,如下示例: YYYY YYYY-MM YYYY-MM-DD 验证必须确保日期格式正确且日期存在 我知道Java8提供了一个新的日期API,所以我想知道它是否能够完成这样的工作 有没有更好的方法使用Java8DateAPI? 使用带有宽松参数的Calendar类仍然是一种好做法吗?要验证YYYY-MM-DD格式,您只需使用JDK 8以来的java.time中引入的 从文本字符串获取LocalDate的实例,例如 2007-12-03. 字符串必须表示有效日期,并使用 Da
YYYY
YYYY-MM
YYYY-MM-DD
验证必须确保日期格式正确且日期存在
我知道Java8提供了一个新的日期API,所以我想知道它是否能够完成这样的工作
有没有更好的方法使用Java8DateAPI?
使用带有宽松参数的Calendar类仍然是一种好做法吗?要验证
YYYY-MM-DD
格式,您只需使用JDK 8以来的java.time
中引入的
从文本字符串获取LocalDate的实例,例如
2007-12-03.
字符串必须表示有效日期,并使用
DateTimeFormatter.ISO\u本地\u日期
如果日期无效,将抛出一个
对于您提供的其他两种格式,将抛出异常。这是合乎逻辑的,因为它们不是真实的日期,只是日期的一部分
LocalDate还提供了(int year、int month、int dayOfMonth)的方法
,
因此,如果您确实想在某些情况下验证年份,在另一种情况下验证月份所在的年份,或者验证完整日期,则可以执行以下操作:
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种格式。您可以使用
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;
}
使用可选字段和
我理解,您只想验证,但之后您很可能希望以适当的方式提取数据。幸运的是,正如您所写,Java8提供了这样一种方法,parseBest
parseBest
适用于可选字段。因此,请首先定义要解析的格式:yyyy[-MM[-dd]]
,并用括号([
和]
)包装可选字段
parseBest
还要求您提供几个TemporalQuery
。实际上,它只是一个围绕模板方法R queryFrom(TemporalAccessor)
的函数包装器。因此,我们实际上可以将临时查询定义为Year::from
。好:那正是我们想要的。问题是,parseBest
的名称不是很好:它将按顺序解析所有内容,并在匹配的第一个适当的TemporalQuery
之后停止。所以在你的情况下,我们必须从最精确到不太精确。以下是您要处理的各种类型:LocalDate
、YearMonth
和Year
。因此,让我们将TemporalQuery[]
定义为LocalDate::from,YearMonth::from,Year::from
。现在,如果parseBest
无法识别您的输入,它将抛出异常
总之,我们将按照如下方式构造parseBest
:
parseBest(DateTimeFormatter.ofPattern("yyyy[-MM[-dd]]"), LocalDate::from, YearMonth::from, Year::from);
public static boolean isValidDate(String dateAsString) {
try {
parseDate(dateAsString);
return true;
} catch (DateTimeParseException e) {
return false;
}
}
因此,让我们正确地写它:
static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy[-MM[-dd]]");
static TemporalAccessor parseDate(String dateAsString) {
return FORMATTER.parseBest(dateAsString, LocalDate::from, YearMonth::from, Year::from);
}
但是。。。您只想验证。。。那么在这种情况下,一个日期被计算出来,昂贵的工作已经完成了。那么,让我们按照如下方式定义验证:
parseBest(DateTimeFormatter.ofPattern("yyyy[-MM[-dd]]"), LocalDate::from, YearMonth::from, Year::from);
public static boolean isValidDate(String dateAsString) {
try {
parseDate(dateAsString);
return true;
} catch (DateTimeParseException e) {
return false;
}
}
我知道,使用异常来处理这样的情况是不好的,但是虽然当前的API非常强大,但是没有考虑到这个非常具体的情况,所以让我们继续使用它
但现在,我们遇到了这个问题:可以解析无效日期。例如,“2018-15”
将被解析为年{2018}
,因为年
是解析器可以使用的最好的临时附件:年月
将失败,但它是年月
,因此根据这一点,它必须是有效的。让我们在格式化程序中再次传递它
public static boolean isValidDate(String dateAsString) {
try {
TemporalAccessor date = parseDate(dateAsString);
return FORMATTER.format(date).equals(dateAsString);
} catch (DateTimeParseException e) {
return false;
}
}
以下是完整的代码:
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 {
TemporalAccessor parsedDate = parseDate(dateAsString);
return FORMATTER.format(parsedDate).equals(dateAsString);
} catch (DateTimeParseException e) {
return false;
}
}
public static void main(String[] args) {  
String[] datesAsString = {
"2018",
"2018-05",
"2018-05-22",
"abc",
"2018-",
"2018-15",
};
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
2018-15: invalid
你想要的不仅仅是验证,比如获取实际值?
请注意,您仍然可以使用从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
}
但要小心,因为如前所述,“2018-15”
仍将被解析,因为年{2018}
而不是年{2018,15}
,或“2018-02-30”
仍将被解析为年
月
而不是本地日期
您可以使用lenient,如果默认值为true:
简化格式
SimpleDateFormat sdf = new SimpleDateFormat(dateFromat);
sdf.setLenient(false);
或在JSON验证中:
@JsonFormat(lenient = OptBoolean.FALSE)
请使用下面的代码。这将验证并适用于每种格式
public class DateValidator {
public static void main(String[] args) {
String datetoCheck = "999999";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyMMdd");
try {
LocalDate localDate = LocalDate.parse(datetoCheck, formatter);
System.out.println(localDate);
} catch ( DateTimeException ex ) {
ex.printStackTrace();
}
}
}
您希望“YYYY”的日期是什么?“YYYY-01-01”?“YYYY-MM”也有同样的问题。使用Calendar
class从来都不是一个好的实践DateFormat
始终是要使用的工具。您应该使用中引入的新工具。您应该避免前面的Java8日期实用程序,如“代码>日历>代码>。如果YYYY,确认今年“存在”(OK…我们可以考虑每个YYYY年存在……)如果您想测试表单,ReGEX是很好的。但是,如果您想测试详细内容,如2222-33-44
或2000-02-30
,那么它很可能会失败。我们如何使用parseBest验证两种格式“yyyy-MM-dd[\'T\HH:MM:SSX]”?当试图验证它时,它只是将它转换为LocalDate并切分时间部分。@Vishwaksena我相信你的问题本身就值得一个完整的问题,而不仅仅是一个评论。请确保指定要使用parseBest
。如果月份无效,此操作将失败“2018-15”@PanditBiradar这是个什么问题?“2018-15”无效,必须失败!