5

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.

2 Answers 2

7

Try SimpleDateFormat. You simply set a format such as the one in your example and then call parse on your dateStr.

Sign up to request clarification or add additional context in comments.

3 Comments

You must make sure that setLenient() is set to false, otherwise you wind up with the same issues as Timestamp.
Thanks Adam. It worked fine but not before calling the setLenient(false) on the SimpleDateFormat object. Thanks for that pointer, Spencer !
Also, be advised that SimpleDateFormat.parse() is not Thread-safe. So if you're doing this in say a servlet, you cannot have a static instance of your SimpleDateFormat, and will have to manage it accordingly.
1

java.time

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

ONLINE DEMO

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.

If at all, you need an instance of 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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.