Reputation: 93
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
Reputation: 86139
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);
}
Upvotes: 1
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
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