Reputation: 27496
I came across a code snippet like this:
Timestamp expiryDate = Timestamp.valueOf(dateStr + " " + "23:59:59.000");
Here dateStr is a string entered by the user in a form, in the format yyyy-mm-dd. Now the behavior of Timestamp.valueOf is such that it converts non-existent dates into appropriate proper dates. Say 31st June 2008 into 01st July 2008.
How can I check in Java if the dateStr string is in fact a valid date ? I know I can manually do the check, but what I would like to know is whether any method is already available to do the same.
Upvotes: 5
Views: 6833
Reputation: 79580
The java.util
Date-Time API and their formatting API, SimpleDateFormat
are outdated and error-prone. Since java.sql.Timestamp
extends java.util.Date
, it has got the same problems. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Solution using java.time
, the modern Date-Time API: You can define a DateTimeFormatter
with ResolverStyle
as ResolverStyle.STRICT
, which is ResolverStyle.SMART
by default.
Demo:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
import java.time.format.ResolverStyle;
import java.time.format.SignStyle;
import java.time.temporal.ChronoField;
import java.util.Locale;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf =
new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR, 1, 4, SignStyle.NORMAL)
.appendLiteral('-')
.appendValue(ChronoField.MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL)
.appendLiteral('-')
.appendValue(ChronoField.DAY_OF_MONTH, 1, 2, SignStyle.NORMAL)
.appendLiteral(' ')
.appendValue(ChronoField.HOUR_OF_DAY, 1, 2, SignStyle.NORMAL)
.appendLiteral(':')
.appendValue(ChronoField.MINUTE_OF_HOUR, 1, 2, SignStyle.NORMAL)
.appendLiteral(':')
.appendValue(ChronoField.SECOND_OF_MINUTE, 1, 2, SignStyle.NORMAL)
.optionalStart()
.appendLiteral('.')
.appendFraction(ChronoField.NANO_OF_SECOND, 0, 3, false)
.optionalEnd()
.toFormatter(Locale.ENGLISH)
.withResolverStyle(ResolverStyle.STRICT);
// Test
Stream.of(
"2008-06-31 23:59:59.000",
"2008-06-30 23:59:59.000",
"2008-6-30 23:59:59.000",
"2008-6-8 23:59:59.000",
"2008-6-8 2:59:59.000",
"2008-6-8 23:5:59.000",
"2008-6-8 23:59:9.000",
"2008-06-30 23:59:59"
).forEach (s -> {
try {
LocalDateTime ldt = LocalDateTime.parse(s, dtf);
System.out.println(ldt);
}catch(DateTimeParseException e) {
System.out.printf("%s is an invalid date-time string.%n", s);
// ...
}
});
}
}
Output:
2008-06-31 23:59:59.000 is an invalid date-time string.
2008-06-30T23:59:59
2008-06-30T23:59:59
2008-06-08T23:59:59
2008-06-08T02:59:59
2008-06-08T23:05:59
2008-06-08T23:59:09
2008-06-30T23:59:59
Learn more about the modern Date-Time API from Trail: Date Time. Check this answer and this answer to learn how to use java.time
API with JDBC.
java.sql.Timestamp
:You can convert a LocalDateTime
into java.sql.Timestamp
using Timestamp#valueOf
e.g.
LocalDateTime now = LocalDateTime.now();
Timestamp ts = Timestamp.valueOf(now);
* If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time
.
Upvotes: 1
Reputation: 16303
Try SimpleDateFormat. You simply set a format such as the one in your example and then call parse on your dateStr.
Upvotes: 7