0

Is there a way to validate these three date formats when they are taken in as an input?

  • "03/03/2000"
  • "03-03-2000"
  • "3rd march 2000"

I managed to come up with a regex for the first 2.

\\d{2}/\\d{2}/\\d{4}
\\d{2}-\\d{2}-\\d{4}

Every approach I took to the third one using regex had a major flaw. regex will only check the format but not whether the date is a valid date. Is there a way to check the format and validity of these 3 date formats?

It is important for this application to take suffixes into account.

  • check this https://stackoverflow.com/q/4024544/7499069. Probably you can find your answer – tuhin47 Mar 19 '22 at 04:50
  • 2
    [Possible duplicate](https://stackoverflow.com/questions/20231539/java-check-the-date-format-of-current-string-is-according-to-required-format-or/20232680#20232680) – MadProgrammer Mar 19 '22 at 05:14
  • I think you'll find it hard to valid `3rd` (or `2nd` or `4th`) as this is not a format specifier generally supported by the APIs – MadProgrammer Mar 19 '22 at 05:28
  • @MadProgrammer we can parse it with `DateTimeFormatter formatter = new DateTimeFormatterBuilder().parseCaseInsensitive().appendPattern("d MMMM yyyy").toFormatter();` – Udesh Mar 19 '22 at 06:20
  • @DevParzival But `st`, `nd`, `rd`, `th` aren't generally used elements of the formatters in Java, so, as you've done, they need to be removed – MadProgrammer Mar 19 '22 at 06:24
  • @MadProgrammer you are right hence I am removing them(`st, nd, rd, th`) using `str.replaceAll("(?<=\\d)(st|nd|rd|th)", "")` – Udesh Mar 19 '22 at 06:27

2 Answers2

3

What the follow does is, tests to see if a given format can parse the String to a LocalDate OR LocalDateTime. If it can (do either), it will the compare the result of formatting either of those results against the original input, just to be sure (because date/time handling is just so much fun).

The intention is to not just determine if the values are within the specified formats, but also to verify if they are actually valid date/time values, because 99/99/0000 is a valid format, but isn't a valid date (except to SimpleDateFormat ‍♂️)

The parsing and comparisons are case insensitive.

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
import java.util.Locale;

public final class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        String[] formats = new String[] { 
            "dd/MM/yyyy",
            "dd-MM-yyyy",
            "d MMMM yyyy"
        };

        String[] values = new String[] {
            "03/03/2000",
            "03-03-2000",
            "3rd march 2000"
        };

        for (String value : values) {
            String fixedValue = value.replaceAll("(?<=\\d)(st|nd|rd|th)", "");
            boolean isValid = isValid(formats, fixedValue, Locale.ENGLISH);
            System.out.println(value + " is valid = " + isValid);
        }
    }

    public boolean isValid(String[] formats, String value, Locale locale) {
        for (String format : formats) {
            if (isValidDate(format, value, locale) || isValidDateTime(format, value, locale)) {
                return true;
            }
        }
        return false;
    }

    public boolean isValid(String format, String value, Locale locale) {
        return isValidDate(format, value, locale) || isValidDateTime(format, value, locale);
    }

    public boolean isValidDateTime(String format, String value, Locale locale) {
        try {
            DateTimeFormatter fomatter = new DateTimeFormatterBuilder()
                    .parseCaseInsensitive()
                    .appendPattern(format)
                    .toFormatter(locale);
            LocalDateTime ldt = LocalDateTime.parse(value, fomatter);
            return ldt.format(fomatter).equalsIgnoreCase(value);
        } catch (DateTimeParseException | java.time.temporal.UnsupportedTemporalTypeException exp) {
            return false;
        }
    }

    public boolean isValidDate(String format, String value, Locale locale) {
        try {
            DateTimeFormatter fomatter = new DateTimeFormatterBuilder()
                    .parseCaseInsensitive()
                    .appendPattern(format)
                    .toFormatter(locale);
            LocalDate ld = LocalDate.parse(value, fomatter);
            return ld.format(fomatter).equalsIgnoreCase(value);
        } catch (DateTimeParseException | java.time.temporal.UnsupportedTemporalTypeException exp) {
            return false;
        }
    }
}

which outputs

03/03/2000 is valid = true
03-03-2000 is valid = true
3rd march 2000 is valid = true

ps: Thanks Dev Parzival for the regular expression, that save a lot of time

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
1

use SimpleDateFormat to validate

Formatting date using SimpleDateFormat doesn't support suffix (st, nd, rd and th) so we have to replace if they are present in the string .

Formatting using SimpleDateFormat

SimpleDateFormat is a concrete class for formatting and parsing dates in a locale-sensitive manner. It allows for formatting (date -> text), parsing (text -> date), and normalization.

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

class MainClass{
    public static void main(String ... $){
        System.out.println(isValidDate("03/03/2000"));
        System.out.println(isValidDate("03-03-2000"));
        System.out.println(isValidDate("3rd march 2000"));
    }
    public static boolean isValidDate(String str){
        boolean match = false;
        try{
            Date date =new SimpleDateFormat("dd/MM/yyyy").parse(str.replaceAll("(?<=\\d)(st|nd|rd|th)", ""));
            return true;
        }catch(ParseException e){
            //System.out.println(e);
            match=false;
        }
        try{
            Date date =new SimpleDateFormat("dd-MM-yyyy")
                .parse(str.replaceAll("(?<=\\d)(st|nd|rd|th)", ""));
            return true;
        }catch(ParseException e){
            //System.out.println(e);
            match=false;
        }
        try{
            Date date =new SimpleDateFormat("d MMMM yyyy")
                .parse(str.replaceAll("(?<=\\d)(st|nd|rd|th)", ""));
            return true;
        }catch(ParseException e){
            //System.out.println(e);
            match = false;
        }
        return match;
    }
}

Formatting using DateTimeForFormatter

import java.time.format.DateTimeFormatter;
import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.time.format.DateTimeFormatterBuilder;

class MainClass{
    public static void main(String ... $){
        System.out.println(isValidDate("03/03/2000"));
        System.out.println(isValidDate("03-03-2000"));
        System.out.println(isValidDate("3rd march 2000"));
    }
    public static boolean isValidDate(final String str){
        try{
            DateTimeFormatter formatter =
                DateTimeFormatter.ofPattern("dd/MM/yyyy");
            LocalDate date = LocalDate.parse(str, formatter);
            return true;
        }catch(DateTimeParseException e){
            //System.out.println(e);
        }
        try{
            DateTimeFormatter formatter =
                DateTimeFormatter.ofPattern("dd-MM-yyyy");
            LocalDate date = LocalDate.parse(str, formatter);
            return true;
        }catch(DateTimeParseException e){
            //System.out.println(e);
        }
        try{
            DateTimeFormatter formatter =
                new DateTimeFormatterBuilder().parseCaseInsensitive().appendPattern("d MMMM yyyy").toFormatter();
            LocalDate date = LocalDate.parse(str.replaceAll("(?<=\\d)(st|nd|rd|th)", ""), formatter);
            return true;
        }catch(DateTimeParseException e){
            //System.out.println(e);
        }
        return false;
    }
}
Udesh
  • 2,415
  • 2
  • 22
  • 32