Dodge_X
Dodge_X

Reputation: 93

Java String to DateTime parse issue

I have a record which have an abnormal DateTime String '20170-09-17',I tried to parse it into DateTime but it didn't throw any Exceptions and this record can not put into MySQL as well...

        DateFormat fmt =new SimpleDateFormat("yyyy-MM-dd");
        System.out.println(fmt.parse("20170-09-17"));

What to do with this data?

Upvotes: 2

Views: 770

Answers (3)

Anonymous
Anonymous

Reputation: 86139

java.time

I always recommend to use java.time, the modern Java date and time API, for date work. In this case it makes your task pretty simple.

    String abnormalInput = "20170-09-17";
    LocalDate date = LocalDate.parse(abnormalInput);
    System.out.println(date);

This throws the exception that you had expected:

Exception in thread "main" java.time.format.DateTimeParseException: Text '20170-09-17' could not be parsed at index 0

We don’t even need to specify any formatter. Your expected input is in ISO 8601 format (link at the bottom), and LocalDate parses ISO 8601 as its default. And throws an exception if the text to parse does not adhere to the format. It can accept a year with more than four digits, but then only with a sign (minus or plus). Because the standard says so.

The range check that Andreas suggests in his answer could still be a good idea. I suggest that you set the limits not by what MySQL can handle but by what can be considered correct in your domain. For the sake of an example:

    LocalDate today = LocalDate.now(ZoneId.of("Asia/Shanghai"));
    if (date.getYear() < today.getYear() - 5 || date.isAfter(today)) {
        throw new IllegalStateException("Date is out of range: " + date);
    }

Links

Upvotes: 1

Michael Gantman
Michael Gantman

Reputation: 7792

SimpleDateFormat and Date are outdated classes. If you use java 8 or higher please switch to DateTimeFormatter class and classes like LocalDate LocalDateTime or any of their "brothers"

Upvotes: 0

Andreas
Andreas

Reputation: 159086

SimpleDateFormat doesn't know the supported range of year where the date will be stored, so you need to validation the date.

Since you mentioned MySQL, and the DATETIME data type supports years in range 1000-9999, you should do this:

static Date parseDate(String dateStr) throws ParseException {
    // Parse the string (strict)
    DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
    fmt.setLenient(false); // Reject invalid month and day values
    Date date = fmt.parse(dateStr);
    
    // Validate year
    Calendar cal = Calendar.getInstance();
    cal.setTime(date);
    int year = cal.get(Calendar.YEAR);
    if (year < 1000 || year > 9999)
        throw new IllegalArgumentException("Invalid year: \"" + dateStr + "\"");
    
    return date;
}

The important parts are:

  • Turn on strict parsing mode, to ensure month and day values are in valid ranges.

  • Custom check to ensure year value is in valid range.


It might be better if you could use the newer Java 8+ Time API, in which case the code would be:

static LocalDate parseDate(String dateStr) {
    DateTimeFormatter fmt = DateTimeFormatter.ofPattern("uuuu-MM-dd")
            .withResolverStyle(ResolverStyle.STRICT);
    LocalDate date = LocalDate.parse(dateStr, fmt);
    if (date.getYear() < 1000 || date.getYear() > 9999)
        throw new DateTimeException("Invalid value for Year (valid values 1000 - 9999): " + date.getYear());
    return date;
}

Same as before: Strict parsing and custom year range check.

Upvotes: 0

Related Questions