如何在java中检查date

我觉得很奇怪,在Java中创buildDate对象的最明显的方式已经被弃用,似乎已经被“取代”,不太明显的使用宽松的日历。 所以…

你如何检查一个date,月份和年份的组合是一个有效date? 例如2008-02-31(如yyyy-mm-dd)的date将是无效date。

目前的方式是使用日历类。 它有setLenient方法,将validationdate和抛出和exception,如果它超出范围,如你的例子。

忘了补充:如果你得到一个日历实例,并使用你的date设置时间,这是如何得到validation。

Calendar cal = Calendar.getInstance(); cal.setLenient(false); cal.setTime(yourDate); try { cal.getTime(); } catch (Exception e) { System.out.println("Invalid date"); } 

关键是df.setLenient(false); 。 这对于简单情况来说已经足够了。 如果你正在寻找一个更强大的(我怀疑)和/或像乔达时间的替代库,然后看看这里(不是接受的答案,但来自用户名为“tardate”的答案): 如何在java中检查date

 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; } } 

如@Maglob所示,基本的方法是使用SimpleDateFormat.parsetesting从string到date的转换。 这将收到无效的日/月组合,如2008-02-31。

但是,实际上这很less,因为SimpleDateFormat.parse非常自由。 有两种行为你可能会关心:

datestring中的字符无效令人惊讶的是,例如,2008-02-2x将以“locale format =”yyyy-MM-dd“作为有效date”传递“。 即使isLenient == false。

年:2位,3位或4位数字? 您可能还希望执行4位数年份,而不是允许默认的SimpleDateFormat行为(根据您的格式是“yyyy-MM-dd”还是“yy-MM-dd”,它将不同地解释“12-02-31” )

标准库的严格解决scheme

所以一个完整的stringdatetesting可能看起来像这样:正则expression式匹配,然后强制date转换的组合。 正则expression式的诀窍是让它对locale友好。

  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); 

请注意,正则expression式假定格式string只包含日,月,年和分隔符。 除此之外,格式可以是任何区域设置格式:“d / MM / yy”,“yyyy-MM-dd”等等。 当前语言环境的格式string可以像这样获得:

 Locale locale = Locale.getDefault(); SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance(DateFormat.SHORT, locale ); String format = sdf.toPattern(); 

乔达时间 – 更好的select?

最近我一直听到乔达的时间,并认为我会比较。 两点:

  1. 似乎更好的是在严格datestring中的无效字符,不像SimpleDateFormat
  2. 看不到一种方法来执行4位数字年(但我想你可以创build自己的DateTimeFormatter为此目的)

使用非常简单:

 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; } 

你可以使用SimpleDateFormat

比如像这样的东西:

 boolean isLegalDate(String s) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); sdf.setLenient(false); return sdf.parse(s, new ParsePosition(0)) != null; } 

java.time

使用Java 8及更高版本中内置的date和时间API ( java.time类),可以使用LocalDate类。

 public static boolean isDateValid(int year, int month, int day) { boolean dateIsValid = true; try { LocalDate.of(year, month, day); } catch (DateTimeException e) { dateIsValid = false; } return dateIsValid; } 

TL;博士

使用java.time.DateTimeFormatter上的严格模式来parsingLocalDate 。 陷阱为DateTimeParseException

 LocalDate.parse( "31/02/2000" , DateTimeFormatter.ofPattern ( "dd/MM/uuuu" ) .withResolverStyle ( ResolverStyle.STRICT ) ) 

parsing后,您可能会检查合理的价值。 例如,最近一百年内的出生date。

 birthDate.isAfter( LocalDate.now().minusYears( 100 ) ) 

避免遗留的date时间类

避免使用最早版本的Java附带的麻烦的旧date时间类。 现在由java.time类取代。

LocalDateDateTimeFormatterResolverStyle

LocalDate类代表没有时间和没有时区的只有date的值。

 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枚举中定义的三种宽松模式中的任何一种来parsingstring。 我们在上面的代码中插入一行来尝试每种模式。

 f = f.withResolverStyle ( ResolverStyle.LENIENT ); 

结果:

  • ResolverStyle.LENIENT
    ld:2000-03-02
  • ResolverStyle.SMART
    ld:2000-02-29
  • ResolverStyle.STRICT
    错误:java.time.format.DateTimeParseException:文本'31 / 02/2000'无法parsing:无效date'FEBRUARY 31'

我们可以看到,在ResolverStyle.LENIENT模式下,无效date向前移动了相同的天数。 在ResolverStyle.SMART模式(默认)下,合理决定将date保持在月份内,并且在闰年的2月29日这个月的最后一天,因为那个月没有第31天。 ResolverStyle.STRICT模式抛出一个exception,抱怨没有这样的date。

所有这三个都是合理的,这取决于您的业务问题和政策。 听起来就像在你的情况下,你想严格模式拒绝无效的date,而不是调整。

关于java.time

java.time框架内置于Java 8及更高版本中。 这些类取代了麻烦的旧date时间类,如java.util.Date.Calendarjava.text.SimpleDateFormat

Joda-Time项目现在处于维护模式 ,build议迁移到java.time。

要了解更多信息,请参阅Oracle教程 。 并search堆栈溢出了很多例子和解释。

大部分的java.timefunction在ThreeTen-Backport中移植到Java 6&7中,并进一步适用于ThreeTenABP中的 Android (请参阅如何使用… )。

ThreeTen-Extra项目将java.time扩展到其他类。 这个项目是未来可能增加java.time的一个试验场。 你可能会在这里find一些有用的类,比如IntervalYearWeekYearQuarter 等等 。

使用标准库的另一个严格的解决scheme是执行以下操作:

1)使用你的模式创build一个严格的SimpleDateFormat

2)尝试使用格式对象parsing用户input的值

3)如果成功,使用相同的date格式(从(1))重新格式化(2)得到的date

4)将重新格式化的date与原始的用户input值进行比较。 如果他们相等,那么input的值严格符合您的模式。

这样,你不需要创build复杂的正则expression式 – 在我的情况下,我需要支持所有的SimpleDateFormat的模式语法,而不是仅限于几天,几个月和几年的某些types。

build立在@Pangea的答案来解决@ceklock指出的问题,我添加了一个方法来validationdateString不包含任何无效的字符。

这是我的方式:

 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+"); } 

我build议你使用apache的org.apache.commons.validator.GenericValidator类。

GenericValidator.isDate(String value, String datePattern, boolean strict);

注意:strict – 是否与datePattern完全匹配。

假设这两个都是string(否则它们已经是有效的date),这里有一个方法:

 package cruft; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class DateValidator { private static final DateFormat DEFAULT_FORMATTER; static { DEFAULT_FORMATTER = new SimpleDateFormat("dd-MM-yyyy"); DEFAULT_FORMATTER.setLenient(false); } public static void main(String[] args) { for (String dateString : args) { try { System.out.println("arg: " + dateString + " date: " + convertDateString(dateString)); } catch (ParseException e) { System.out.println("could not parse " + dateString); } } } public static Date convertDateString(String dateString) throws ParseException { return DEFAULT_FORMATTER.parse(dateString); } } 

这是我得到的输出:

 java cruft.DateValidator 32-11-2010 31-02-2010 04-01-2011 could not parse 32-11-2010 could not parse 31-02-2010 arg: 04-01-2011 date: Tue Jan 04 00:00:00 EST 2011 Process finished with exit code 0 

正如你所看到的,它确实处理你的两个案例。

这对我很好。 本文上面提出的方法。

 private static boolean isDateValid(String s) { SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); try { Date d = asDate(s); if (sdf.format(d).equals(s)) { return true; } else { return false; } } catch (ParseException e) { return false; } } 

我认为simpliest只是将一个string转换成一个date对象,并将其转换回一个string。 给定的datestring没有问题,如果两个string仍然匹配

 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; } 

关于使用SimpleDateFormat的两点评论

如果声明为静态访问,则应该将其声明为静态实例,因为它不是线程安全的

IME更好地为每个date的parsing实例化一个实例。

上面的dateparsing方法是不错的,我只是在现有的方法中添加新的检查,使用formater仔细检查转换date与原始date,所以它几乎适用于每个案件,因为我validation。 例如02/29/2013是无效的date。 给定函数根据当前可接受的date格式分析date。 如果date未成功parsing,则返回true。

  public final boolean validateDateFormat(final String date) { String[] formatStrings = {"MM/dd/yyyy"}; boolean isInvalidFormat = false; Date dateObj; for (String formatString : formatStrings) { try { SimpleDateFormat sdf = (SimpleDateFormat) DateFormat.getDateInstance(); sdf.applyPattern(formatString); sdf.setLenient(false); dateObj = sdf.parse(date); System.out.println(dateObj); if (date.equals(sdf.format(dateObj))) { isInvalidFormat = false; break; } } catch (ParseException e) { isInvalidFormat = true; } } return isInvalidFormat; } 

以下是我使用无外部库的Node环境:

 Date.prototype.yyyymmdd = function() { var yyyy = this.getFullYear().toString(); var mm = (this.getMonth()+1).toString(); // getMonth() is zero-based var dd = this.getDate().toString(); return zeroPad([yyyy, mm, dd].join('-')); }; function zeroPad(date_string) { var dt = date_string.split('-'); return dt[0] + '-' + (dt[1][1]?dt[1]:"0"+dt[1][0]) + '-' + (dt[2][1]?dt[2]:"0"+dt[2][0]); } function isDateCorrect(in_string) { if (!matchesDatePattern) return false; in_string = zeroPad(in_string); try { var idate = new Date(in_string); var out_string = idate.yyyymmdd(); return in_string == out_string; } catch(err) { return false; } function matchesDatePattern(date_string) { var dateFormat = /[0-9]+-[0-9]+-[0-9]+/; return dateFormat.test(date_string); } } 

这里是如何使用它:

 isDateCorrect('2014-02-23') true 
 // to return valid days of month, according to month and year int returnDaysofMonth(int month, int year) { int daysInMonth; boolean leapYear; leapYear = checkLeap(year); if (month == 4 || month == 6 || month == 9 || month == 11) daysInMonth = 30; else if (month == 2) daysInMonth = (leapYear) ? 29 : 28; else daysInMonth = 31; return daysInMonth; } // to check a year is leap or not private boolean checkLeap(int year) { Calendar cal = Calendar.getInstance(); cal.set(Calendar.YEAR, year); return cal.getActualMaximum(Calendar.DAY_OF_YEAR) > 365; }