79

I wanted to know that is there any method available in Java that can do this.Otherwise I may go for Regex solution.

I have input string from user that can be any characters. And I want to check that the input string is according to my required date format or not.

As I have input 20130925 and my required format is dd/MM/yyyy so, for this case I should get false.

I don't want to convert this date I just want to check whether input string is according to required date format or not.



I have tried following

Date date = null;
try {
date = new SimpleDateFormat("dd/MM/yyyy").parse("20130925");
} catch (Exception ex) {
// do something for invalid dateformat
}

but my catch (Exception ex) block is unable to catch any exceptions generated by SimpleDateFormat.Parse();

Elvin
  • 2,131
  • 8
  • 23
  • 25
  • 1
    Your example code is now outdated. Those troublesome old date-time classes are now legacy. Supplanted by the java.time classes. – Basil Bourque Sep 11 '17 at 05:44

8 Answers8

131

Disclaimer

Parsing a string back to date/time value in an unknown format is inherently impossible (let's face it, what does 3/3/3 actually mean?!), all we can do is "best effort"

Important

This solution doesn't throw an Exception, it returns a boolean, this is by design. Any Exceptions are used purely as a guard mechanism.

2018

Since it's now 2018 and Java 8+ has the date/time API (and the rest have the ThreeTen backport). The solution remains basically the same, but becomes slightly more complicated, as we need to perform checks for:

  • date and time
  • date only
  • time only

This makes it look something like...

public static boolean isValidFormat(String format, String value, Locale locale) {
    LocalDateTime ldt = null;
    DateTimeFormatter fomatter = DateTimeFormatter.ofPattern(format, locale);

    try {
        ldt = LocalDateTime.parse(value, fomatter);
        String result = ldt.format(fomatter);
        return result.equals(value);
    } catch (DateTimeParseException e) {
        try {
            LocalDate ld = LocalDate.parse(value, fomatter);
            String result = ld.format(fomatter);
            return result.equals(value);
        } catch (DateTimeParseException exp) {
            try {
                LocalTime lt = LocalTime.parse(value, fomatter);
                String result = lt.format(fomatter);
                return result.equals(value);
            } catch (DateTimeParseException e2) {
                // Debugging purposes
                //e2.printStackTrace();
            }
        }
    }

    return false;
}

This makes the following...

System.out.println("isValid - dd/MM/yyyy with 20130925 = " + isValidFormat("dd/MM/yyyy", "20130925", Locale.ENGLISH));
System.out.println("isValid - dd/MM/yyyy with 25/09/2013 = " + isValidFormat("dd/MM/yyyy", "25/09/2013", Locale.ENGLISH));
System.out.println("isValid - dd/MM/yyyy with 25/09/2013 12:13:50 = " + isValidFormat("dd/MM/yyyy", "25/09/2013  12:13:50", Locale.ENGLISH));
System.out.println("isValid - yyyy-MM-dd with 2017-18--15 = " + isValidFormat("yyyy-MM-dd", "2017-18--15", Locale.ENGLISH));

output...

isValid - dd/MM/yyyy with 20130925 = false
isValid - dd/MM/yyyy with 25/09/2013 = true
isValid - dd/MM/yyyy with 25/09/2013 12:13:50 = false
isValid - yyyy-MM-dd with 2017-18--15 = false

Original Answer

Simple try and parse the String to the required Date using something like SimpleDateFormat

Date date = null;
try {
    SimpleDateFormat sdf = new SimpleDateFormat(format);
    date = sdf.parse(value);
    if (!value.equals(sdf.format(date))) {
        date = null;
    }
} catch (ParseException ex) {
    ex.printStackTrace();
}
if (date == null) {
    // Invalid date format
} else {
    // Valid date format
}

You could then simply write a simple method that performed this action and returned true when ever Date was not null...

As a suggestion...

Updated with running example

I'm not sure what you are doing, but, the following example...

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class TestDateParser {

    public static void main(String[] args) {
        System.out.println("isValid - dd/MM/yyyy with 20130925 = " + isValidFormat("dd/MM/yyyy", "20130925"));
        System.out.println("isValid - dd/MM/yyyy with 25/09/2013 = " + isValidFormat("dd/MM/yyyy", "25/09/2013"));
        System.out.println("isValid - dd/MM/yyyy with 25/09/2013 12:13:50 = " + isValidFormat("dd/MM/yyyy", "25/09/2013  12:13:50"));
    }

    public static boolean isValidFormat(String format, String value) {
        Date date = null;
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            date = sdf.parse(value);
            if (!value.equals(sdf.format(date))) {
                date = null;
            }
        } catch (ParseException ex) {
            ex.printStackTrace();
        }
        return date != null;
    }

}

Outputs (something like)...

java.text.ParseException: Unparseable date: "20130925"
isValid - dd/MM/yyyy with 20130925 = false
isValid - dd/MM/yyyy with 25/09/2013 = true
isValid - dd/MM/yyyy with 25/09/2013 12:13:50 = false
    at java.text.DateFormat.parse(DateFormat.java:366)
    at javaapplication373.JavaApplication373.isValidFormat(JavaApplication373.java:28)
    at javaapplication373.JavaApplication373.main(JavaApplication373.java:19)

Not correct. For isValidFormat("yyyy-MM-dd", "2017-18--15"); not throw any Exception.

isValid - yyyy-MM-dd", "2017-18--15 = false

Seems to work as expected for me - the method doesn't rely on (nor does it throw) the exception alone to perform it's operation

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • 1
    I have tried that before but I am unable to understand that from no way catch block is unable to catch that exception. I have tried again after your answer and same issue I am passing date in mm/dd/yyyy format intentionally and it is not coming in catch block. – Elvin Nov 27 '13 at 02:49
  • try { date=new SimpleDateFormat("dd/MM/yyyy").parse(sDOB); } catch (ParseException e) { System.out.println(e.toString()); } – Elvin Nov 27 '13 at 02:49
  • Actually my catch block is unable to catch any Exception generated by SimpleDateFormat.Parse() even i Have tried Parent Exception class catch (Exception e){} – Elvin Nov 27 '13 at 03:30
  • First of all, ignore the execution and check the state of date value, second, it works for me java.text.ParseException: Unparseable date: "20130925" at java.text.DateFormat.parse(DateFormat.java:357) at Ideone.main(Main.java:15) – MadProgrammer Nov 27 '13 at 05:47
  • After excution of this line date = new SimpleDateFormat("dd/MM/yyyy").parse("20130925"); my code just break. – Elvin Nov 27 '13 at 07:10
  • What do you mean by "break"... – MadProgrammer Nov 27 '13 at 07:15
  • break means code exit from this point. No lines of code executed after that – Elvin Nov 28 '13 at 07:20
  • Have you tried the additional isValid method? – MadProgrammer Nov 28 '13 at 07:20
  • @MadProgrammer This is not correct. Javadoc for `DateFormat.parse()` says: _"The method may not use the entire text of the given string."_ So e.g. it will report true also for `25/09/2013-suffix` – mnicky Jun 09 '15 at 12:05
  • @mnicky I think the problem we have is the part where it says *"may not"*. So, so long as the input starts with the correct value, it would pass? – MadProgrammer Jun 09 '15 at 12:49
  • 1
    @mnicky Okay, so formatted the resulting `Date` (using the same pattern) and checked it against the original. It beats using regular expression, which could "validate" invalidate dates :P – MadProgrammer Jun 09 '15 at 12:56
  • why is this answer not accepted??? Thanks for this! :D – Fritz May 18 '16 at 09:45
  • Nice trick. Acceptable answer. – dinesh028 Jul 07 '16 at 16:18
  • I'm left scratching my head as to while this might attract a downvote, if there is something missing, it would be helpful to comment about how it doesn't meet the user's requirements or answers their question or even in how it might be improved – MadProgrammer Sep 02 '16 at 03:08
  • @MadProgrammer This solution is wrong for two reasons: It accepts strings that have trailing characters and it accepts invalid dates without throwing an exception (it returns a Date with an unexpected value). Example: Try out "2016/12/07" with format "MM/dd/yy" and you'll end up with 12/12/2174. This is due to it treating 2016 as the number of months added to the value, which is 167 years, 12 months, which then gets added to 2007. Ick. To prevent this: sdf.setLenient(false); – Tyler Hoppe Dec 07 '16 at 23:46
  • 1
    @TylerHoppe Actually, there is an internal test, which takes the resulting `Date`, formats against the supplied `format` and checks to see if the result matches the original `value`, in your case, this will return `false`, meaning the format doesn't match the value supplied. I've even tried with leading and trailing characters and it continues to return `false` (as I would expect it to) – MadProgrammer Dec 08 '16 at 00:03
  • My bad; didn't actually read the implementation. :) Still has some issues though due to the differences between parse and format: Try "yy-MM" and "2016-01". The result should be true. – Tyler Hoppe Dec 08 '16 at 00:17
  • @TylerHoppe The whole process is wrought with issues :P. And `2016` doesn't meet the requirements of `yy`, It'd have to be `16` or `yyyy` ... – MadProgrammer Dec 08 '16 at 00:28
  • Why not use [setLenient](http://docs.oracle.com/javase/6/docs/api/java/text/DateFormat.html#setLenient(boolean)) with a parameter of `false` instead of parsing then re-formatting? – D.B. Dec 28 '16 at 17:10
  • 1
    @D.B. Because it would allow dates which don't match the format to pass as true as TylerHoppe was trying to do, but I didn't see that as the original question, the question was about matching dates to a particular format, so this is a strict match – MadProgrammer Dec 28 '16 at 20:49
  • @D.B. And don't get me started on dates like 3/3/3 – MadProgrammer Dec 28 '16 at 21:01
  • I'd love to know why this might be downvoted - in what ways does it not answer the OPs question, in what ways could it be improved? – MadProgrammer May 05 '17 at 21:50
  • Not correct. `For isValidFormat("yyyy-MM-dd", "2017-18--15");` not throw any Exception. See [below](https://stackoverflow.com/a/26133606/4244605). – t0m Jun 05 '17 at 15:27
  • @t0m `isValid - "yyyy-MM-dd", "2017-18--15" = false` - Seems to work as expected - the method is not relying on the exception alone to perform its operation – MadProgrammer Jun 05 '17 at 19:34
  • @MadProgrammer ah, OK. I rolled back vote down. – t0m Jun 06 '17 at 07:48
  • I love how ever challenge to the answer has been proven wrong, yet people still seem willing to down vote it, I’d be curious as to know why – MadProgrammer Jun 29 '17 at 19:57
  • I am just wondering if `3/3/3` is correct example here. IF we can assume that it is mix of *day*, *month* and *year*, then since they all have same value (`3`) their order will not matter if format is based only on `d` `M` and `y` as all its permutations will parse it into same date. If I understood intention of that example correctly maybe it will be worth changing it into something like `1/2/3` which if parsed with `d/M/y` or `M/d/y` will result different dates. – Pshemo Aug 30 '19 at 09:09
  • @Pshemo It would depend on context, for example, if you’re looking for a “matching” format, then this is going to give mixed results. The intention is to demonstrate that there isn’t a “right” answer – MadProgrammer Aug 30 '19 at 09:19
  • OK, fair enough. – Pshemo Aug 30 '19 at 09:24
47

For your case, you may use regex:

boolean isValidFormat = input.matches("([0-9]{2})/([0-9]{2})/([0-9]{4})");

For a larger scope or if you want a flexible solution, refer to MadProgrammer's answer.

Edit

Almost 5 years after posting this answer, I realize that this is a stupid way to validate a date format. But i'll just leave this here to tell people that using regex to validate a date is unacceptable

Det
  • 3,640
  • 5
  • 20
  • 27
Baby
  • 5,062
  • 3
  • 30
  • 52
  • 1
    This is the good way to do it! Other methods are old school... – Clemzd Mar 20 '15 at 13:20
  • 32
    @Clemzd Except you can do something like '99/99/9999` which obviously isn't valid ;P – MadProgrammer May 29 '15 at 23:36
  • 2
    I need regular expression to satisfy both formats like 2015-9-18 and 2015-09-18 –  Nov 27 '15 at 10:30
  • How about 12 September 2016, 3 Aug 16, 06 October 2015 – Yan Khonski Aug 12 '16 at 11:25
  • 1
    You could do this inline like `checkformat = input.matches("([0-9]{2})/([0-9]{2})/([0-9]{4})")` – luiscosta Jul 30 '18 at 10:33
  • 1
    No way! This can be the most genius solution & supported by all APIs if we develop it more, like adding `String[] t = value.split("/"); return (Integer.valueOf(t[0]) <= 31 && Integer.valueOf(t[1]) <= 12);` of cource we can use `switch case` for number of days for different months. – Taufik Nur Rahmanda Oct 22 '18 at 07:26
24

You can try this to simple date format valdation

 public Date validateDateFormat(String dateToValdate) {

    SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HHmmss");
    //To make strict date format validation
    formatter.setLenient(false);
    Date parsedDate = null;
    try {
        parsedDate = formatter.parse(dateToValdate);
        System.out.println("++validated DATE TIME ++"+formatter.format(parsedDate));

    } catch (ParseException e) {
        //Handle exception
    }
    return parsedDate;
}
Janahan
  • 401
  • 8
  • 20
  • 1
    This worked for me. Pretty simple. Thanks! – Emiliano Zilocchi Apr 01 '16 at 19:14
  • FYI, the terribly troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/10/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html), and `java.text.SimpleDateFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes built into Java 8 and later. See [*Tutorial* by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Aug 11 '18 at 18:40
  • It worked for me. The only perfect solution. – Fawad Khaliq May 14 '20 at 18:48
19
DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
formatter.setLenient(false);
try {
    Date date= formatter.parse("02/03/2010");
} catch (ParseException e) {
    //If input date is in different format or invalid.
}

formatter.setLenient(false) will enforce strict matching.

If you are using Joda-Time -

private boolean isValidDate(String dateOfBirth) {
        boolean valid = true;
        try {
            DateTimeFormatter formatter = DateTimeFormat.forPattern("dd/MM/yyyy");
            DateTime dob = formatter.parseDateTime(dateOfBirth);
        } catch (Exception e) {
            valid = false;
        }
        return valid;
    }
tiwari.vikash
  • 367
  • 3
  • 6
4

Here's a simple method:

public static boolean checkDatePattern(String padrao, String data) {
    try {
        SimpleDateFormat format = new SimpleDateFormat(padrao, LocaleUtils.DEFAULT_LOCALE);
        format.parse(data);
        return true;
    } catch (ParseException e) {
        return false;
    }
}
Alberto Cerqueira
  • 1,339
  • 14
  • 18
2

For example, if you want the date format to be "03.11.2017"

 if (String.valueOf(DateEdit.getText()).matches("([1-9]{1}|[0]{1}[1-9]{1}|[1]{1}[0-9]{1}|[2]{1}[0-9]{1}|[3]{1}[0-1]{1})" +
           "([.]{1})" +
           "([0]{1}[1-9]{1}|[1]{1}[0-2]{1}|[1-9]{1})" +
           "([.]{1})" +
           "([20]{2}[0-9]{2})"))
           checkFormat=true;
 else
           checkFormat=false;

 if (!checkFormat) {
 Toast.makeText(getApplicationContext(), "incorrect date format! Ex.23.06.2016", Toast.LENGTH_SHORT).show();
                }
kksal55
  • 500
  • 7
  • 14
0

A combination of the regex and SimpleDateFormat is the right answer i believe. SimpleDateFormat does not catch exception if the individual components are invalid meaning, Format Defined: yyyy-mm-dd input: 201-0-12 No exception will be thrown.This case should have been handled. But with the regex as suggested by Sok Pomaranczowy and Baby will take care of this particular case.

Pramit
  • 1,373
  • 1
  • 18
  • 27
-1

Regex can be used for this with some detailed info for validation, for example this code can be used to validate any date in (DD/MM/yyyy) format with proper date and month value and year between (1950-2050)

    public Boolean checkDateformat(String dateToCheck){   
        String rex="([0]{1}[1-9]{1}|[1-2]{1}[0-9]{1}|[3]{1}[0-1]{1})+
        \/([0]{1}[1-9]{1}|[1]{1}[0-2]{2})+
        \/([1]{1}[9]{1}[5-9]{1}[0-9]{1}|[2]{1}[0]{1}([0-4]{1}+
        [0-9]{1}|[5]{1}[0]{1}))";

        return(dateToCheck.matches(rex));
    }
theoretisch
  • 1,718
  • 5
  • 24
  • 34
Tonmoy
  • 11