-3

I have an instant field and trying to validate the values in this field using the following approach:

Instant.parse("2021-09-29 09:35:07.531")

However, it throws the error:

java.time.format.DateTimeParseException: Text '2021-09-29 09:35:07.531' could not be parsed at index 10.

So, how can I test if the given Instant date in String format is a valid Instant date?

I am implementing an Import feature and I need to check the date cells. So, the date is normally kept in Instant format in db and for this reason I need to check if the cell date value is a valid Instant date. So, if there is a more proper way, of course I can follow that approach.

I do not use the value, I just need to check if the date is a valid date.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
Jack
  • 1
  • 21
  • 118
  • 236
  • Did you try with the right format Instant.parse("2021-09-29T09:35:07.531Z")? – Neeraj Oct 11 '21 at 14:45
  • I thought it, but the data in my database is in this format like `2021-09-29 11:04:12.683` – Jack Oct 11 '21 at 14:47
  • So, maybe I need to set this format while parsing. Any idea? – Jack Oct 11 '21 at 14:47
  • The exception points to index 10, that's the whitespace in your example `String`. It expects a `T` there. An `Instant` can only be derived from this `String` if you add a `ZoneId` or a `ZoneOffset` at least. – deHaar Oct 11 '21 at 14:58
  • 5
    **Caution:** If you force that string into an Instant, you will be implicitly forcing a timezone which isn’t part of the value, which will probably result in incorrect data. Read it as a LocalDateTime instead: `resultSet.getObject(1, LocalDateTime.class)` – VGR Oct 11 '21 at 15:07
  • *but the data in my database is in this format like …* No, you’re wrong there. Your database *displays* that format. Internally it most likely uses some binary format. – Ole V.V. Oct 11 '21 at 16:10
  • Rather than `datetime` or `timestamp` (without time zone) use the `timestamp with time zone` or `timstamptz` data type of your database (assuming it’s got such, but it’s standard, so it should have). Then you can retrieve either an `Instant` or an `OffsetDateTime`. The latter can be trivially converted to `Instant`. – Ole V.V. Oct 11 '21 at 16:11
  • *I have an instant field* Where?! In your UI? Your database? Your Java program? Your spreadsheet? … – Ole V.V. Oct 11 '21 at 16:14
  • I do not use the value, I just need to check if the date is a valid date. – Jack Oct 12 '21 at 08:01
  • Robert, thanks for providing additional information since yesterday. It’s great that you do and helps a lot. It’s always best to *edit the question and add information there* so we have everything in one place. When you do it in reaction to comments additionally @-tag the person requesting the information in a comment. This will draw that person’s attention (usually). – Ole V.V. Oct 12 '21 at 17:33
  • @OleV.V. Thanks a lot for this wonderful and useful information. I will keep all of them in consideration. Regards. – Jack Oct 13 '21 at 08:21

3 Answers3

1

A reference to the time zone is mandatory if you are trying to use the Instant class. So, let's try this:

LocalDateTime.from(DateTimeFormatter.ofPattern("yyyy-MM-dd H:mm:ss.SSS").parse("2021-09-29 09:35:07.351")).atZone(ZoneId.systemDefault()).toInstant();
Renato
  • 2,077
  • 1
  • 11
  • 22
  • Thanks a lot, but is it possible without using simpledateformat, etc? – Jack Oct 11 '21 at 14:48
  • In my single line code there isn't any `SimpleDateFormat` ref, I'm using only java.time package – Renato Oct 11 '21 at 14:49
  • 1
    I meant `DateTimeFormatter`. – Jack Oct 11 '21 at 14:49
  • And also it is **not working** :( – Jack Oct 11 '21 at 14:49
  • What do you mean with "is not working"? – Renato Oct 11 '21 at 14:50
  • `LocalDateTime.from(DateTimeFormatter.ofPattern("yyyy-MM-dd H:mm:ss.SSS").parse("2021-09-29 09:35:07.531")).atZone(ZoneId.systemDefault()).toInstant();` throws "*Cannot find local variable 'LocalDateTime'*" error – Jack Oct 11 '21 at 14:51
  • 1
    Try with `import java.time.LocalDateTime;` – Renato Oct 11 '21 at 14:52
  • I tried, but does not make any sense. – Jack Oct 11 '21 at 14:55
  • This should work perfectly fine if you import the class(es) you need, @Robert. However, this answer would be even better if the author had mentioned the core problem: `Instant.parse(String s)` only parses ISO date `String`s and an `Instant` can only be derived from a *full* datetime `String` that includes either an offset or a zone. – deHaar Oct 11 '21 at 14:56
  • I've just added this detail in my answer. But your suggestion is more detailed yet – Renato Oct 11 '21 at 14:57
  • 1
    @Renato just add that explanation, maybe choose your own words. – deHaar Oct 11 '21 at 14:59
  • @deHaar Ok, but what about the solution? How can validate an Instant date in String format? – Jack Oct 11 '21 at 15:00
  • 1
    You could check for a `DateTimeParseException` but you cannot use a wrong pattern for that and just leave zone and offset because it would always fail. After a successful parsing, you can check for wrong values if you create a `String` from the `Instant` using the same `DateTimeFormatter` and `ZoneId` or `ZoneOffset` and find out if the `String`s are equal. Just suggestions... – deHaar Oct 11 '21 at 15:04
  • Instead of trying to explain by words, why do not you post an example code to show the correct usage that I need? – Jack Oct 11 '21 at 15:12
  • 4
    @Robert, why don't you try to write some lines of code that reflect the words you read? – Renato Oct 11 '21 at 15:17
1

Your Date-Time string does not have timezone information and therefore you can not parse it into an Instant without introducing a timezone. I recommend you parse it into LocalDateTime and use the same for DB work if it is supposed to be used independent of timezones.

Demo:

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String args[]) {
        DateTimeFormatter dtfInput = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS", Locale.ENGLISH);
        LocalDateTime ldt = LocalDateTime.parse("2021-09-29 09:35:07.531", dtfInput);
        System.out.println(ldt);
    }
}

Output:

2021-09-29T09:35:07.531

ONLINE DEMO

How to use LocalDateTime in JDBC?

Given below is a sample code to insert a LocalDateTime into columnfoo (which is of TIMESTAMP type):

PreparedStatement st = conn.prepareStatement("INSERT INTO mytable (columnfoo) VALUES (?)");
st.setObject(1, ldt);
st.executeUpdate();
st.close();

Given below is a sample code to retrieve a LocalDateTime from columnfoo:

Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT * FROM mytable WHERE <some condition>");
while (rs.next()) {
    // Assuming the column index of columnfoo is 1
    LocalDateTime ldt = rs.getObject(1, LocalDateTime.class));
    System.out.println(ldt);
}
rs.close();
st.close();

In case you want to parse the given Date-Time string into Instant:

As described above, you need to introduce a timezone in order to parse it into an Instant.

Demo:

import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String args[]) {
        // Change the ZoneId to the applicable one e.g. ZoneId.of("Etc/UTC")
        DateTimeFormatter dtfInput = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS", Locale.ENGLISH)
                                        .withZone(ZoneId.systemDefault());

        Instant instant = Instant.from(dtfInput.parse("2021-09-29 09:35:07.531"));
        System.out.println(instant);
    }
}

Output in my timezone, Europe/London:

2021-09-29T08:35:07.531Z

ONLINE DEMO

Learn more about the modern Date-Time API* from Trail: Date Time.


* 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.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
1

So, how can I test if the given Instant date in String format is a valid Instant date?

It is not.

An instant is a (unique) point in time. Your string holds a date and time of day. Without knowing the time zone this may denote some point within a range of 24 or 27 hours — so pretty far from being one point in time.

Edit: I understand that you are importing the string from somewhere, that you cannot decide the format or content of the string, and you need to validate it. You can validate it as a date and time. You basically cannot convert it to an Instant, or at least you only can under assumptions the validity of which I can’t know. For validation I suggest this formatter:

private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder()
        .append(DateTimeFormatter.ISO_LOCAL_DATE)
        .appendLiteral(' ')
        .append(DateTimeFormatter.ISO_LOCAL_TIME)
        .toFormatter(Locale.ROOT);

The formatter reuses built-in formatters and accepts a variable number of decimals in the seconds, which I think will make sense in many contexts. You know better whether it does in yours.

Validate like this:

    String importedDateTimeString = "2021-09-29 09:35:07.531";
    try {
        LocalDateTime.parse(importedDateTimeString, PARSER);
        System.out.format("Valid date and time: %s%n", importedDateTimeString);
    } catch (DateTimeParseException dtpe) {
        System.out.format("Not a valid date and time: %s. Validation error: %s%n",
                importedDateTimeString, dtpe);
    }

Output:

Valid date and time: 2021-09-29 09:35:07.531

Original recommendation: So instead use a format that includes offset from UTC. In particular the ISO 8601 format for an instant in UTC is a recommended option for several purposes, like 2021-09-29T01:35:07.531Z.

Link: Wikipedia article: ISO 8601

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • Thanks for useful explanations. You right, but I cannot change the date format and for this reason I have to check this format (`2021-09-29 09:35:07.531`) as a string. Is that impossible by some conversion as well? – Jack Oct 12 '21 at 05:41
  • Sorry, your question still isn’t clear to me. If you convert the string to something else, is it then the string you are checking? And what are the reason for and the purpose of the validation? Does this answer your question? [How to sanity check a date in Java](https://stackoverflow.com/questions/226910/how-to-sanity-check-a-date-in-java) – Ole V.V. Oct 12 '21 at 05:45
  • I am implementing an Import feature and I need to check the date cells. So, the date is normally kept in Instant format in db and for this reason I need to check if the cell date value is a valid Instant date. So, if there is a more proper way, of course I can follow that approach but I have no prior experience :( – Jack Oct 12 '21 at 05:54
  • Thanks, that helps. I have edited the answer to fit with what I understood from your comment. – Ole V.V. Oct 12 '21 at 06:04