简体   繁体   中英

Is it ncessary to use Regex to check date sanity in addition to SimpleDateFormat.parse?

I've seen the following code and I'm confused about the use of Regex here. The requirement of this checkDateSanity method is:

The DATE format is dd.MM.yyyy. (WARNING: the DATE must exist!!)

   private boolean checkDateSanity(String dateString) {
    if (Pattern.matches("[0-3][0-9].[0-1][0-9].[0-9]{4}", dateString)) {
        try {
            DateFormat df = new SimpleDateFormat(DATE_FORMAT);
            df.setLenient(false);
            df.parse(dateString);
            return true;
        } catch (ParseException e) {
            return false;
        }
    }

    return false;
}

I've read this post on a similar topic How to sanity check a date in Java , where the answer simply uses

        try {
            DateFormat df = new SimpleDateFormat(DATE_FORMAT);
            df.setLenient(false);
            df.parse(dateString);
            return true;
        } catch (ParseException e) {
            return false;
        }

I did some random tests and the Regex doesn't make any difference with or without it. Is there any deeper reason to have the Regex check here? Like to reduce the computation cost? If that's the case, is it really worth it?

Define 'valid'.

The regex, for example, allows For the 39th day of the 19th month, as well as the 0th day of the 0th month: 39-19-0000 is a valid date according to it, but 1-1-2020 is not (only 01-01-2020 would be).

The SDF is old API that you shouldn't use (use java.time ), but as far as this code goes, lenience is turned off, so it does not accept 39-19-0000 , though it would accept 1-1-2020 .

Combining the two gets you the strictest take, but it sure feels convoluted. Is there a particular heinous issue with accepting 1-1-2020 ?

But note this gigantic problem : Year confusion. 1-1-99 WILL parse with a .setLenient(false) SDF with pattern dd.MM.yyyy , and is interpreted as jan 1st during the year 99, sometime during the days of the roman empire (not like the prince song).

For that purpose alone, that regex is quite useful; you can use the regexp to error out if a 2-digit year is passed, as SDF can't reject that kind of input.

Thus, the real advice!

Those old date apis are so incredibly bad. They suck. Do not use them. Update your IDE, mark down SimpleDateFormat as illegal. Here is the java time package, doing precisely what you want. Note that SDF returns a java.util.Date which is a lying liar who lies: That represent an instant in time and has no business representing dates. It really doesn't - that's why all the various .getYear() etc methods are deprecated.

LocalDate x = LocalDate.parse("01.01.1999", DateTimeFormatter.ofPattern("dd.MM.yyyy"));
System.out.println(x);
> 1999-01-01

// Awesome. It's an actual _DATE_ and not a timestamp where timezones
// can mess everything up.

LocalDate x = LocalDate.parse("01.01.99", DateTimeFormatter.ofPattern("dd.MM.yyyy"));
> Exception in thread "main" java.time.format.DateTimeParseException: Text '01.01.1999' could not be parsed

// perfect. it crashes, as it should.

LocalDate x = LocalDate.parse("1.1.1999", DateTimeFormatter.ofPattern("dd.MM.yyyy"));
> Exception in thread "main" java.time.format.DateTimeParseException: Text '01.01.1999' could not be parsed

// if you want `1.1.1999` to crash, well, you can.

LocalDate x = LocalDate.parse("1.1.1999", DateTimeFormatter.ofPattern("d.M.yyyy"));
System.out.println(x);
> 1999-01-01

// but you don't have to. with just `d`, 1 parses as 1, so does 01.

You can go with yy too, which FORCES that you only use 2 digits; they are all interpreted as 20xx. (1.1.99 is 2099-01-01).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM