0

I have found nice function which is validating the format and correctness of date String. I wanted to upgrade it to validate only >= 1900 years.

So this is what I found:

public boolean isDateValid(String date) {
    try {
        DateFormat df = new SimpleDateFormat("dd-MM-yyyy");
        df.setLenient(false);
        df.parse(date);
        return true;
    } catch (ParseException e) {
        return false;
    }
}

And this is my upgraded version:

public boolean isDateValid(String date) {
    try {
        DateFormat df = new SimpleDateFormat("dd-MM-yyyy");
        df.setLenient(false);
        df.parse(date);
        Integer year = Integer.parseInt(date.substring(6, 10));
        if (year>= 1900)
            return true;
        else
            return false;
    } catch (ParseException e) {
        return false;
    }
}

So instead of returning true I am checking if the year variable is greater or equal to 1900. The problem is when I run this function with "12-12-1xxx" (edit: or "12-12-1abc"). NumberFormatException is thrown while parsing year String to int. It definitely should not happen because ParseException should be thrown first, breaking the try {} block.

It looks like validation from first listing does not work properly because it accepts every "yyyy" part which begins with a number. Yet everything works fine for "12-12-xxxx" (edit: or "12-12-abcd").

EDIT:

Stop voting down my question and focus while you are reading. The question is very clear: why new SimpleDateFormat("dd-MM-yyyy").parse("12-12-1xxx") does not throw a ParseException?

Wojciech Kazior
  • 1,208
  • 8
  • 15
  • 1
    it's working fine on my system , check your input and use latest JDK – Pavneet_Singh Sep 23 '16 at 09:51
  • i can post a snapshot (only as an answer) but it'll make no sense so check for any invalid input – Pavneet_Singh Sep 23 '16 at 09:56
  • yes it is working on my system too. – chalitha geekiyanage Sep 23 '16 at 09:58
  • What don't you understand? Instead of returning true, I additionally want to check if the year is >=1900. Here there is a NumberFormatException, which should not happen. – Wojciech Kazior Sep 23 '16 at 10:06
  • 2
    The problem here is the *DateFormat.parse()* method. *"The method may not use the entire text of the given string."* as it is stated in the JavaDoc. – Alexander Sep 23 '16 at 10:09
  • 1
    @Am_I_Helpful Slow down, my friend. The question is very clear: Why `new SimpleDateFormat("dd-MM-yyyy").parse("12-12-1xxx")` does not throw a ParseException? – Little Santi Sep 23 '16 at 10:09
  • @LittleSanti this is exactly what I mean! For everyone who does not understand the problem: when I say that the function does not work for "12-12-1xxx" I mean "12-12-[NUMBER][CHAR][CHAR][CHAR]". – Wojciech Kazior Sep 23 '16 at 10:28
  • @Alexander this is exactly what I needed to know, thanks! – Wojciech Kazior Sep 23 '16 at 10:34
  • @WojciechKazior Perhaps you would avoid the down-votes if (a) the title of your Question accurately described your issue, and (b) if you opened the Question with a *summary of the goal and obstruction* rather than talking about validating >= 1900 years. I have read your question at least five times and am still not sure if your goal is to throw an exception when parsing an input date string that has characters as part of the year. – Basil Bourque Sep 23 '16 at 21:22
  • @BasilBourque I understand your point of view, but I just wanted to introduce everyone to my problem, showing the background of it. The question crystallized a bit when I was writing it. Thanks for response, I will try to be more concrete next time. In my opinion some people did not understand the "12-12-1xxx" part. They thought that by the 'x' I mean any number - but in fact, it is literally a character. I just wanted to know why ParseException is not thrown for such a String. Cheers! – Wojciech Kazior Sep 24 '16 at 06:26

4 Answers4

2

As I understand from javadoc the SimpleDateFormat will take 1 as valid part of the year and will parse it. Instead you can try to validate date with regular expressions. You can find some examples here Regex to validate date format dd/mm/yyyy

Community
  • 1
  • 1
Stan
  • 1,398
  • 9
  • 14
1

The documentation of the parse method is:

Parses text from the beginning of the given string to produce a date. The method may not use the entire text of the given string.

Because the whole string does not need to be used, then "12-12-1xxx" is actually parsed as "12-12-1", and you get a year 1 date.

Instead of using the substring, you could use the result of the parse method to get the year. getYear is depreciated and returns an offset from 1900 so you might want to convert to a Calendar or LocalDate first.

public boolean isDateValid(String date) {
    try {
        DateFormat df = new SimpleDateFormat("dd-MM-yyyy");
        df.setLenient(false);
        Date parsed = df.parse(date);
        int year = parsed.getYear() + 1900;
        if (year >= 1900)
            return true;
        else
            return false;
    } catch (ParseException e) {
        return false;
    }
}
fgb
  • 17,739
  • 2
  • 33
  • 50
  • Thanks for explaining why "parse" method do not throw exception. I think I will catch NumberFormatException in addition. Anyway, thanks for your proposition. – Wojciech Kazior Sep 23 '16 at 11:18
0

I have check your function, and find below details.

If you will pass 12-12-1xxx in main function then also you will get true it will not return false even when I print the date output which is converted by df.parse(date) is Oct 10 00:00:00 GMT 2.

So you will not get parse exception anytime for this,

Suggestion

Either you change ParseException by Exception or also use catch for NumberFormatException as below.

 public boolean isDateValid(String date) {
    try {
        DateFormat df = new SimpleDateFormat("dd-MM-yyyy");
        df.setLenient(false);
        df.parse(date);
        Integer year = Integer.parseInt(date.substring(6, 10));
        if (year>= 1900)
            return true;
        else
            return false;
    } catch (Exception e) { // Use Exception or if you want ParseException then use below commented code
        return false;
    }
    /*catch (NumberFormatException nfe) { // Use this if you use ParseException
        return false;
    }*/
 }
Vickyexpert
  • 3,066
  • 4
  • 17
  • 34
  • 1
    This does not explain why a ParseException is not thrown when an invalid input is entered. Moreover: Catching `Exception` is a bad practice, because it includes whatever RuntimeExceptions may arise. – Little Santi Sep 23 '16 at 10:11
  • check this one https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html you will get idea why you are not getting error as it will consider this kind of text in date according to their criteria – Vickyexpert Sep 23 '16 at 10:17
  • @LittleSanti this is not invalid input and therefor I have show output of that parsed date also, as java doc considering it as date check above link – Vickyexpert Sep 23 '16 at 10:19
  • @Vickyexpert ok, so "12-12-1xxx" or "12-12-1abc" is treated as valid format - but you did not explain why. Catching NumberFormatException can be good solution, I also thought about it. Thanks for advices! – Wojciech Kazior Sep 23 '16 at 10:50
0

If anybody is interested in how the code should look like, here it is:

public boolean isDateValid(String date, String format) {
    if (date.length()!=format.length())
        return false;
    try {
        DateFormat df = new SimpleDateFormat(format);
        df.setLenient(false);

        df.parse(date); // exception is not thrown if day and month is
                        // correct AND the first char of year is a digit

        // so if we have correct day and correct month
        // and we know the year has 4 chars we can try to parse it
        Integer year = Integer.parseInt(date.substring(6, 10));

        if (year>= 1900 && year<=2015) // here we know that the year is 4 digit integer
            return true;               // and we can limit it
        else
            return false;

    } catch (ParseException e) {
        return false;
    } catch (NumberFormatException e) {
        return false;
    }
}
Wojciech Kazior
  • 1,208
  • 8
  • 15