Whats the recommended way to validate ISO8601 datetime string in java
Asked Answered
G

4

7

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?

Groff answered 16/11, 2020 at 16:29 Comment(2)
Try to parse it with a DateTimeFormatter, using one of the ISO_... constants.Spurt
ISO 8601 has a lot of freedoms and extensions that may be agreed upon between the exchanging parties. E.g., basic and extended format, years with more than 4 digits, comma or dot as decimal separator, offset from UTC with or without colon between hours and minutes. Which variants do you want to accept?Ben
B
7

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

Ben answered 16/11, 2020 at 19:53 Comment(0)
E
6

Assuming you are using at least Java 8 the simplest way to do so would be something like this:

private static boolean isIsoDate(String date) {
    try {
        Instant.from(DateTimeFormatter.ISO_INSTANT.parse(date));
        return true;
    } catch (DateTimeParseException e) {
        //log the failure here
        e.printStackTrace();
    }
    return false;
}

Conversely you can validate the format using a regex but this is way harder that the above mentioned way.

As for your other question, the easiest way would be to first convert your date string to a concrete Date object and then follow the recommendations here:

Compare Date object with a TimeStamp in Java

Evadne answered 16/11, 2020 at 16:44 Comment(1)
doesnt account for all variations of ISO, specifically a problem for timezonesAtkinson
D
1

form java 8 later you can use DateTimeFormatter class to check for a format, so I defined a method to check whether its in ISO format or not:

boolean isValidISODateTime(String date) {
    try {
        java.time.format.DateTimeFormatter.ISO_DATE_TIME.parse(date);
        return true;
    } catch (java.time.format.DateTimeParseException e) {
        return false;
    }
}
Dissert answered 16/11, 2020 at 16:47 Comment(0)
A
-4
public static boolean isValidISODateTime(String date){
        try {
            LocalDateTime.parse(date, DateTimeFormatter.ISO_DATE_TIME);
            return true;
        } catch (DateTimeParseException e) {
            return false;
        }
    }
Aggress answered 14/9, 2022 at 8:48 Comment(1)
Thanks for wanting to contribute. Your are repeating an existing answer with a minor improvement without any explanation of what the change is nor what difference it makes. Also DateTimeFormatter.ISO_DATE_TIME will not validate whether UTC offset or time zone ID is present. While the former is optional in ISO 8601, for most purposes you will want to control whether it is there or not. The time zone ID is not allowed in ISO 8601, so you want to forbid it. Sorry, this is no good answer.Ben

© 2022 - 2024 — McMap. All rights reserved.