Search code examples
javadatetimedatetime-formatiso8601

Whats the recommended way to validate ISO8601 datetime string in java


I am using java 11. Wanted to know whats the best(Most importantly Recommended) way to validate if the datetime string is ISO8601 complaint in java.

Also how to compare this string value with java.sql.Timestamp?


Solution

  • ISO 8601 is so many things, so I am not going to write an exhaustive answer. I am trying to give an overview of the options that you will likely choose from. After that you should research the relevant one/s further. And maybe before doing that you will need to research what ISO 8601 is, what it can sometimes be and what it isn’t.

    For many (most) purposes trying to parse your string with built-in means of java.time, the modern Java date and time API, will give you a satisfactory validation, as already stated in the other answers. Options are:

    • Simpler and most often enough: Use the one-arg parse method of the appropriate date-time class from java.time. They generally parse ISO 8601 format and throw a DateTimeParseException if the string is not in ISO 8601 format. Depending on the information required to be present in your string (date and/or time, UTC offset) you may for example use OffsetDateTime.parse() or LocalDate.parse().
    • For special or exotic needs use one of the ISO_XXXX constants of the DateTimeFormatter class.

    There are at least three ways that the above may not be enough for you:

    1. The built-it means mentioned parse and accept the most common ISO 8601 variants. For example, OffsetDateTime.parse(CharSequence) requires a colon in the offset from UTC (if it is not Z), as in +07:00. ISO 8601 also allows the offset to be written without a colon, as in +0700. If you need to accommodate variants not covered by the built-in means, building your own DateTimeFormatter will probably be a good and not too complicated solution. You may use the DateTimeForamtter.ofPattern method or a DateTimeFormatterBuilder.
    2. The built-in means sometimes allow values that you may not want to allow. For example in strict ISO 8601 a year is between 1583 and 9999 inclusive. The classes of java.time allow years from -999 999 999 through +999 999 999. Your solution is a range check after parsing. The date-time classes have methods isBefore and isAfter for this.
    3. ISO 8601 includes time intervals for which java.time offers no class nor formatter, including repeating time intervals. If you want to allow these, you may look for a different date and time library (Time4J and ThreeTen Extra come to mind) or you will have to do some more work yourself to validate.

    How to compare to a java.sql.Timestamp?

    If you can avoid using java.sql.Timestamp, do. That class is poorly designed and long outdated. Since JDBC 4.2 we prefer fetching timestamps as OffsetDateTime or LocalDateTime from our SQL databases.

    If you have got a Timestamp from a legacy API that you cannot afford to upgrade just now, convert each to an Instant and compare them using isBefore() or isAfter(). Here’s an example:

        String yourIso8601String = "2020-11-17T02:51:39.375109+07:00";
        Timestamp ts = Timestamp.from(Instant.parse("2020-11-16T19:00:00Z"));
        
        OffsetDateTime odt = OffsetDateTime.parse(yourIso8601String);
        boolean isBeforeTimestamp = odt.toInstant().isBefore(ts.toInstant());
        System.out.println("Is the ISO 8601 string before the Timestamp? " + isBeforeTimestamp);
    

    Output from the example is:

    Is the ISO 8601 string before the Timestamp? false

    Links