我觉得很奇怪,在Java中创建Date
对象最明显的方式已经被弃用,并似乎被一个不太容易使用的宽容日历所替代。
如何检查作为日、月和年组合给出的日期是否是有效日期?
例如,2008-02-31(即yyyy-mm-dd)将是无效日期。
我觉得很奇怪,在Java中创建Date
对象最明显的方式已经被弃用,并似乎被一个不太容易使用的宽容日历所替代。
如何检查作为日、月和年组合给出的日期是否是有效日期?
例如,2008-02-31(即yyyy-mm-dd)将是无效日期。
关键在于df.setLenient(false);
。这对于简单情况已经足够了。如果您正在寻找更健壮的(我怀疑)和/或类似joda-time的替代库,那么请查看用户“tardate”的答案
final static String DATE_FORMAT = "dd-MM-yyyy";
public static boolean isDateValid(String date)
{
try {
DateFormat df = new SimpleDateFormat(DATE_FORMAT);
df.setLenient(false);
df.parse(date);
return true;
} catch (ParseException e) {
return false;
}
}
setLenient
:SimpleDateFormat
将始终解析直到匹配模式并忽略字符串的其余部分,因此您会得到 201
作为年份。 - Daniel Naberjava.util.Date
、java.util.Calendar
和 java.text.SimpleDateFormat
等旧的日期时间类现已成为遗留系统,并已被 Java 8 及以上版本内置的 java.time 类所取代。请参阅 Oracle 的 教程。 - Basil Bourque正如@Maglob所示,基本方法是使用SimpleDateFormat.parse测试从字符串到日期的转换。这将捕获无效的日/月组合,如2008-02-31。
然而,在实践中,这通常是不够的,因为SimpleDateFormat.parse非常宽容。有两种行为可能会让您担心:
日期字符串中存在无效字符 令人惊讶的是,例如使用locale格式 =“yyyy-MM-dd”,甚至当isLenient == false时,2008-02-2x也将“通过”作为有效日期。
年份:2、3或4位数字? 您可能还想强制执行4位数字的年份,而不是允许默认的SimpleDateFormat行为(这将根据您的格式是“yyyy-MM-dd”还是“yy-MM-dd”而以不同方式解释“12-02-31”)。
因此,完整的字符串转日期测试可能看起来像这样:正则表达式匹配和强制日期转换的组合。正则表达式的技巧是使其符合语言环境。
Date parseDate(String maybeDate, String format, boolean lenient) {
Date date = null;
// test date string matches format structure using regex
// - weed out illegal characters and enforce 4-digit year
// - create the regex based on the local format string
String reFormat = Pattern.compile("d+|M+").matcher(Matcher.quoteReplacement(format)).replaceAll("\\\\d{1,2}");
reFormat = Pattern.compile("y+").matcher(reFormat).replaceAll("\\\\d{4}");
if ( Pattern.compile(reFormat).matcher(maybeDate).matches() ) {
// date string matches format structure,
// - now test it can be converted to a valid date
SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance();
sdf.applyPattern(format);
sdf.setLenient(lenient);
try { date = sdf.parse(maybeDate); } catch (ParseException e) { }
}
return date;
}
// used like this:
Date date = parseDate( "21/5/2009", "d/M/yyyy", false);
请注意该正则表达式假定格式字符串仅包含日、月、年和分隔符字符。除此之外,格式可以是任何区域设置格式,例如:"d/MM/yy","yyyy-MM-dd"等等。可以像这样获取当前区域设置的格式字符串:
Locale locale = Locale.getDefault();
SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance(DateFormat.SHORT, locale );
String format = sdf.toPattern();
最近我听说了 joda time ,并且想进行比较。以下是两个要点:
它非常容易使用:
import org.joda.time.format.*;
import org.joda.time.DateTime;
org.joda.time.DateTime parseDate(String maybeDate, String format) {
org.joda.time.DateTime date = null;
try {
DateTimeFormatter fmt = DateTimeFormat.forPattern(format);
date = fmt.parseDateTime(maybeDate);
} catch (Exception e) { }
return date;
}
Date
,SimpleDateFormat
等)现已被现代java.time类所取代。同样,Joda-Time项目处于维护模式,并建议迁移到java.time类。 - Basil Bourque使用严格模式和java.time.DateTimeFormatter
来解析LocalDate
。捕获DateTimeParseException
异常。
LocalDate.parse( // Represent a date-only value, without time-of-day and without time zone.
"31/02/2000" , // Input string.
DateTimeFormatter // Define a formatting pattern to match your input string.
.ofPattern ( "dd/MM/uuuu" )
.withResolverStyle ( ResolverStyle.STRICT ) // Specify leniency in tolerating questionable inputs.
)
在解析后,您可能需要检查合理的值。例如,一个出生日期在过去一百年内。
birthDate.isAfter( LocalDate.now().minusYears( 100 ) )
避免使用最早版本的Java中附带的麻烦的旧日期时间类。现在已经被java.time类所取代。
LocalDate
& DateTimeFormatter
& ResolverStyle
LocalDate
类表示仅包含日期值而不包含时间和时区的值。
String input = "31/02/2000";
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "dd/MM/uuuu" );
try {
LocalDate ld = LocalDate.parse ( input , f );
System.out.println ( "ld: " + ld );
} catch ( DateTimeParseException e ) {
System.out.println ( "ERROR: " + e );
}
java.time.DateTimeFormatter
类可以设置为使用ResolverStyle
枚举中定义的任意三种宽容模式解析字符串。我们在上述代码中插入一行以尝试每种模式。
f = f.withResolverStyle ( ResolverStyle.LENIENT );
结果:
ResolverStyle.LENIENT
ResolverStyle.SMART
ResolverStyle.STRICT
ResolverStyle.LENIENT
模式下,无效日期向前移动相同数量的天数。在ResolverStyle.SMART
模式(默认模式)下,会做出一个逻辑决策,将日期保持在该月份内,并选择该月份最后一天,即闰年的2月29日,因为该月没有31日。ResolverStyle.STRICT
模式会抛出异常,指出没有这样的日期。java.time 框架内置于 Java 8 及以后版本。这些类替代了老旧的日期时间类,如 遗留 的 java.util.Date
、Calendar
和 SimpleDateFormat
。
java.sql.*
类。ThreeTen-Extra项目通过增加类扩展了java.time。该项目是java.time可能未来添加的内容的试验场。您可能会在这里找到一些有用的类,例如Interval
, YearWeek
, YearQuarter
和更多。
您可以使用SimpleDateFormat
例如:
boolean isLegalDate(String s) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setLenient(false);
return sdf.parse(s, new ParsePosition(0)) != null;
}
java.util.Date
、java.util.Calendar
和java.text.SimpleDateFormat
这样的旧日期时间类现在已经成为遗留系统,被内置于Java 8及更高版本中的java.time类所取代。请参阅Oracle的教程。 - Basil Bourque目前的方法是使用Calendar类。它具有setLenient方法,该方法将验证日期并在超出范围时引发异常,就像您的示例一样。
忘记添加: 如果您获取一个日历实例并使用您的日期设置时间,这就是您获得验证的方式。
Calendar cal = Calendar.getInstance();
cal.setLenient(false);
cal.setTime(yourDate);
try {
cal.getTime();
}
catch (Exception e) {
System.out.println("Invalid date");
}
java.util.Date
、java.util.Calendar
和 java.text.SimpleDateFormat
这些麻烦的旧日期时间类现在已经过时,被 Java 8 及更高版本内置的 java.time 类所取代。请参见 Oracle 的 教程。 - Basil BourqueResolverStyle.SMART
,该值会将结果调整为有效日期而不是抛出异常。因此,此代码无法实现问题的目标。请参见我的答案,其中包括使用ResolverStyle.STRICT
的示例和解决方案。 - Basil BourqueLocalDate.of()
的工作方式与.withResolverStyle(ResolverStyle.STRICT)
的DateTimeFormatter
非常相似。 - Det在 Aravind的答案 基础上,修复了 ceklock 在评论中指出的问题。我添加了一个方法来验证 dateString
是否包含任何无效字符。
具体做法如下:
private boolean isDateCorrect(String dateString) {
try {
Date date = mDateFormatter.parse(dateString);
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return matchesOurDatePattern(dateString); //added my method
}
catch (ParseException e) {
return false;
}
}
/**
* This will check if the provided string matches our date format
* @param dateString
* @return true if the passed string matches format 2014-1-15 (YYYY-MM-dd)
*/
private boolean matchesDatePattern(String dateString) {
return dateString.matches("^\\d+\\-\\d+\\-\\d+");
}
我认为最简单的方法是将字符串转换为日期对象,然后再将其转换回字符串。如果两个字符串仍然匹配,给定的日期字符串就可以了。
public boolean isDateValid(String dateString, String pattern)
{
try
{
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
if (sdf.format(sdf.parse(dateString)).equals(dateString))
return true;
}
catch (ParseException pe) {}
return false;
}
我建议你使用来自apache的org.apache.commons.validator.GenericValidator
类。
GenericValidator.isDate(String value, String datePattern, boolean strict);
注意: strict - 是否需要严格匹配日期格式。