How to check date match in Java

I'm curious that the most obvious way to create Date objects in Java was deprecated and seems to have been "replaced" not so obvious for using lenient calendar.

How do you check if a date indicated as a combination of day, month and year is a valid date?

For example, 2008-02-31 (as in yyyy-mm-dd) would be an invalid date.

+74
java date validation calendar
Oct 22 '08 at 18:04
source share
20 answers

The current way is to use a calendar class. It has a setLenient method that will check the date, as well as throw and throw if it is out of range, as in your example.

Forgot to add: If you receive a copy of the calendar and set the time using your date, you will receive a confirmation.

 Calendar cal = Calendar.getInstance(); cal.setLenient(false); cal.setTime(yourDate); try { cal.getTime(); } catch (Exception e) { System.out.println("Invalid date"); } 
+30
Oct 22 '08 at 18:08
source share

The key is df.setLenient (false); This is more than enough for simple cases. If you are looking for more reliable (I doubt it) and / or alternative libraries such as joda-time, then look at the answer of the user "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; } } 
+71
Dec 24 '10 at 19:46
source share

As @Maglob shows, the main approach is to check the conversion from string to date using SimpleDateFormat.parse . This will cause invalid day / month combinations to fail, for example 2008-02-31.

However, in practice this is rarely the case since SimpleDateFormat.parse is extremely liberal. You may encounter two types of behavior:

Invalid characters in the date string Surprisingly, 2008-02-2x "will pass" as a valid date with the language format = "yyyy-MM-dd", for example. Even if isLenient == false.

Years: 2, 3 or 4 digits? You can also use 4-digit years, rather than allowing the default behavior of SimpleDateFormat (which will interpret โ€œ12-02-31โ€ differently depending on whether your format was โ€œyyyy-MM-ddโ€ or โ€œyy- MM-dd ",)

Strict solution with standard library

Thus, a full test today might look like this: a combination of regular expression matching, and then a forced date conversion. A regexp trick should make it convenient for localization.

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

Note that the regular expression assumes that the format string contains only the day, month, year, and delimiter characters. In addition, the format can be in any locale format: "d / MM / yy", "yyyy-MM-dd", etc. The format string for the current locale can be obtained as follows:

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

Is Jod's time the best alternative?

I recently heard about joda time and thought I'd compare. Two points:

  • It seems better to strictly observe invalid characters in the date string, unlike SimpleDateFormat
  • It is not possible to see another four years with this (but I think you could create your own DateTimeFormatter for this purpose)

It is quite easy to use:

 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; } 
+47
May 21 '09 at 10:08
source share

You can use SimpleDateFormat

For example, something like:

 boolean isLegalDate(String s) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); sdf.setLenient(false); return sdf.parse(s, new ParsePosition(0)) != null; } 
+37
Oct 22 '08 at 19:35
source share

TL; dr

Use strict mode on java.time.DateTimeFormatter to parse LocalDate . Trap for 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. ) 

After parsing, you can check for an acceptable cost. For example, the date of birth for the last hundred years.

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

Avoid obsolete date and time classes

Avoid using the problematic old date and time classes that ship with the earliest versions of Java. Now superseded by java.time classes.

LocalDate & DateTimeFormatter & ResolverStyle

The LocalDate class represents a value only for a date without a time of day and without a time zone.

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

The java.time.DateTimeFormatter class can be configured to parse strings in any of the three indulgence modes defined in the ResolverStyle enumeration. We insert a line into the code above to try each of the modes.

 f = f.withResolverStyle ( ResolverStyle.LENIENT ); 

Results, achievements:

  • ResolverStyle.LENIENT
    ld: 2000-03-02
  • ResolverStyle.SMART
    ld: 2000-02-29
  • ResolverStyle.STRICT
    ERROR: java.time.format.DateTimeParseException: text "31/02/2000" cannot be parsed: invalid date "FEBRUARY 31"

We see that in ResolverStyle.LENIENT mode, an invalid date moves an equivalent number of days in advance. In ResolverStyle.SMART mode (by default), a logical decision is made to save the date in the month and switch to the last possible day of the month, February 29, in a leap year, since this month does not have a 31st day. The ResolverStyle.STRICT mode throws an exception stating that there is no such date.

All three of them are reasonable depending on your business problem and policy. It seems that in your case, you want strict mode to reject the wrong date, rather than correct it.




About java.time

The java.time framework is built into Java 8 and later. These classes supersede the nasty old obsolete date and time classes, such as java.util.Date , Calendar , and SimpleDateFormat .

The Joda-Time project, currently in maintenance mode , recommends switching to the java.time classes.

To learn more, see the Oracle Tutorial . And a search for many examples and explanations. JSR 310 specification .

You can exchange java.time objects directly with your database. Use a JDBC driver that conforms to JDBC 4.2 or later. No strings needed, no java.sql.* Needed.

Where to get java.time classes?

  • Java SE 8 , Java SE 9 and later
    • Built in.
    • Part of the standard Java API with integrated implementation.
    • Java 9 adds some minor features and fixes.
  • Java SE 6 and Java SE 7
    • Most of the functionality of java.time has been ported to Java 6 and 7 in ThreeTen-Backport .
  • Android
    • Later versions of Android bundle implementations of the java.time classes.
    • For earlier versions of Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP ....

The ThreeTen-Extra project extends java.time with additional classes. This project is a testing ground for possible future additions to java.time. Here you can find some useful classes such as Interval , YearWeek , YearQuarter and others .

+21
Sep 22 '16 at 10:25
source share

java.time

With the Date and Time API ( java.time ) built into Java 8 and later LocalDate , you can use the LocalDate class.

 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; } 
+12
May 02 '14 at 22:55
source share

Based on Arawind 's answer , to fix the problem pointed out by ceklock in his comment , I added a method to make sure that dateString does not contain invalid characters.

Here is how I do it:

 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+"); } 
+7
May 29 '15 at 11:54
source share

An alternative line solution using the standard library is as follows:

1) Create a strict SimpleDateFormat using your template

2) Try to analyze the value entered by the user using the format object

3) If successful, reformat the date obtained as a result of (2) using the same date format (from (1))

4) Compare the reformatted date with the original user-entered value. If they are equal, then the entered value strictly matches your template.

Thus, you do not need to create complex regular expressions - in my case, I needed to support the entire syntax of the SimpleDateFormat template, and not be limited to certain types, such as days, months, and years.

+6
Apr 12 '10 at 2:00
source share

I suggest you use the org.apache.commons.validator.GenericValidator class from apache.

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

Note: strict - there must be an exact match with datePattern.

+4
Jul 17 '13 at 21:33
source share

I think the easiest way is to simply convert the string to a date object and convert it back to string. This date string is perfect if both strings are still the same.

 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; } 
+3
Feb 04 '16 at 9:49
source share

Assuming both of these strings are strings (otherwise they would already be valid dates), here is one way:

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

Here's the output I get:

 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 

As you can see, it does a great job with both cases.

+2
Dec 24 '10 at 19:45
source share

This works great for me. The approach suggested by Ben above.

 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; } } 
+2
Sep 06 '13 at 20:38
source share

Two comments on using SimpleDateFormat.

it must be declared as a static instance, if it is declared as static access, it must be synchronized, since it is not thread safe

IME, which is better than instance instance for each date analysis.

+1
May 21 '09 at 15:03
source share

it seems that SimpleDateFormat does not validate the template strictly even after setLenient (false); a method has been applied to it, so I used the method below to check if the entered date is valid or not according to the provided template.

 import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; public boolean isValidFormat(String dateString, String pattern) { boolean valid = true; DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); try { formatter.parse(dateString); } catch (DateTimeParseException e) { valid = false; } return valid; } 
+1
Jul 30 '19 at 9:04 am
source share

The above date parsing methods are good, I just added a new check for existing methods that double check the converted date with the original date using formater, so it works for almost every case, as I checked. e.g. 02/29/2013 is an invalid date. This function analyzes the date according to the current valid date formats. It returns true if the date is not processed successfully.

  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; } 
0
Mar 13 '13 at 10:11
source share

Here is what I did for a Node environment without external libraries:

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

And here is how to use it:

 isDateCorrect('2014-02-23') true 
0
Sep 01 '16 at 16:51
source share
 // 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; } 
0
Jul 05 '17 at 5:09 on
source share

So I would check the date format:

  public static boolean checkFormat(String dateTimeString) { return dateTimeString.matches("^\\d{4}-\\d{2}-\\d{2}") || dateTimeString.matches("^\\d{4}-\\d{2}-\\d{2}\\s\\d{2}:\\d{2}:\\d{2}") || dateTimeString.matches("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}") || dateTimeString .matches("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z") || dateTimeString.matches("^\\d{4}-\\d{2}-\\d{2}\\s\\d{2}:\\d{2}:\\d{2}Z"); } 
0
Oct 31 '18 at 21:07
source share
  public static String detectDateFormat(String inputDate, String requiredFormat) { String tempDate = inputDate.replace("/", "").replace("-", "").replace(" ", ""); String dateFormat; if (tempDate.matches("([0-12]{2})([0-31]{2})([0-9]{4})")) { dateFormat = "MMddyyyy"; } else if (tempDate.matches("([0-31]{2})([0-12]{2})([0-9]{4})")) { dateFormat = "ddMMyyyy"; } else if (tempDate.matches("([0-9]{4})([0-12]{2})([0-31]{2})")) { dateFormat = "yyyyMMdd"; } else if (tempDate.matches("([0-9]{4})([0-31]{2})([0-12]{2})")) { dateFormat = "yyyyddMM"; } else if (tempDate.matches("([0-31]{2})([az]{3})([0-9]{4})")) { dateFormat = "ddMMMyyyy"; } else if (tempDate.matches("([az]{3})([0-31]{2})([0-9]{4})")) { dateFormat = "MMMddyyyy"; } else if (tempDate.matches("([0-9]{4})([az]{3})([0-31]{2})")) { dateFormat = "yyyyMMMdd"; } else if (tempDate.matches("([0-9]{4})([0-31]{2})([az]{3})")) { dateFormat = "yyyyddMMM"; } else { return "Pattern Not Added"; //add your required regex } try { String formattedDate = new SimpleDateFormat(requiredFormat, Locale.ENGLISH).format(new SimpleDateFormat(dateFormat).parse(tempDate)); return formattedDate; } catch (Exception e) { // return ""; } } 
0
Jul 04 '19 at 12:52 on
source share

setLenient to false if you like strict checking

 public boolean isThisDateValid(String dateToValidate, String dateFromat){ if(dateToValidate == null){ return false; } SimpleDateFormat sdf = new SimpleDateFormat(dateFromat); sdf.setLenient(false); try { //if not valid, it will throw ParseException Date date = sdf.parse(dateToValidate); System.out.println(date); } catch (ParseException e) { e.printStackTrace(); return false; } return true; } 
-one
Jul 05 '19 at 17:28
source share



All Articles