-1

I have a string billedDate which stores date time value from an input. I need to check if it's valid and as per the date time format YYYYMMDDTHHMMSSZ is there any function I can make use? For decimal fields I am using NumberUtils.isParsable which is returning a true or false for the field.

Mahmoud Ben Hassine
  • 28,519
  • 3
  • 32
  • 50
Bhargav G
  • 3
  • 1
  • 2
    Have you tried anything yet? – tnw Feb 16 '21 at 20:55
  • This is very, very difficult. One approach would be to use regular expression, the problem with this is, it doesn't valid the date value, so you could pass in 32 for the month and it would be valid - using a regular expression for validating date/time values is generally a bad idea. Another approach would be to attempt to parse the value to a date/time value (maybe `ZonedDateTime`) and format it back again and compare the results – MadProgrammer Feb 16 '21 at 21:06
  • @MadProgrammer It's not 'very, very difficult'. Just parse it and catch the errors. – user207421 Feb 16 '21 at 22:27
  • @user207421 It is difficult - as I've demonstrated [here](https://stackoverflow.com/questions/20231539/java-check-the-date-format-of-current-string-is-according-to-required-format-or/20232680#20232680) - there's no "absolute" way to guarantee that a string will match the format in an 100% acceptable way - but the question mentioned takes in a format and a string, so it's acceptance criteria is very wide. The best you can do, as I said, is parse the string and re-format it and compare the results – MadProgrammer Feb 16 '21 at 22:52

3 Answers3

3

Use java.time.format.DateTimeFormatter to parse the string. Catch the parsing exception and handle it as a negative response.

P.S. There is no good reason for using SimpleDateFormat, java.util.Date or java.util.Calendar when java.time.* exist, so please don't.

Andrew T
  • 51
  • 3
2

java.time

I recommend java.time, the modern Java date and time API, for your date and time work. I suggest:

private static final DateTimeFormatter formatter
        = DateTimeFormatter.ofPattern("uuuuMMdd'T'HHmmssX")
                .withResolverStyle(ResolverStyle.STRICT);

public static boolean isParseableBasicIso8601(String str) {
    try {
        OffsetDateTime odt = OffsetDateTime.parse(str, formatter);
        return odt.getOffset().equals(ZoneOffset.UTC);
    } catch (DateTimeParseException dtpe) {
        return false;
    }
}

To try it out:

    String[] testStrings = {
            "20210223T234556Z",
            "Cannot be parsed",
            "20210229T234556Z",
            "20210223T234556+08",
            "20210223T234556+00",
    };
    
    for (String s : testStrings) {
        System.out.format("%-18s? %s%n", s, isParseableBasicIso8601(s));
    }

Output is:

20210223T234556Z  ? true
Cannot be parsed  ? false
20210229T234556Z  ? false
20210223T234556+08? false
20210223T234556+00? true

The third example shows that Java knows that 2021 is not a leap year. ResolverStyle.STRICT causes it to reject February 29. In the fourth example the UTC offset is wrong. Accepting the last example is not what you asked for. In ISO 8601 format (which your format is), an offset of zero from UTC is usually denoted Z, but +00 is accepted too. If you want to reject this, the solution is in the comment by Mad Programmer: format the date-time back using the same formatter and only accept if the two strings are equal.

Consider adding a range check and reject dates and times that are unreasonably far in the past or the future. Use OffsetDateTime.isBefore() or isAfter() for comparison.

Links

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
0

The solution seems to be using java's SimpleDateFormat.

SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");

Date parsed = format.parse("11111111T111111Z");

I would also recommend switching to the ISO date format instead. It is just like your proposed format, but with a few extra spacer to make it more future proof and human readable.

Yours: yyyyMMdd'T'HHmmss'Z'
ISO:  yyyy-MM-dd'T'HH:mm'Z'

Reference: https://stackoverflow.com/a/3914498/5987669

Locke
  • 7,626
  • 2
  • 21
  • 41
  • 3
    That is the troublesome and very old-fashioned solution. I recommend that no one uses `SimpleDateFormat`. Use `DateTimeFormatter` from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Feb 16 '21 at 21:30
  • Hello thanks for the solution, but this is throwing an exception if the parsing is unsuccessful. But in my case if it doesn't match the pattern I need to make the field billedDate null. It shouldn't fail. Do you know if there's any way the above function returns boolean to check if the parsing passed or failed? – Bhargav G Feb 16 '21 at 21:31