Vijay Dev
Vijay Dev

Reputation: 27496

Java Timestamp valueOf

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

Answers (2)

Arvind Kumar Avinash
Arvind Kumar Avinash

Reputation: 79580

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.

Upvotes: 1

AdamC
AdamC

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

Related Questions