0

How to convert this string into instant: String date = "Fri Sep 30 00:00:00 IST 2022";

Exception:

java.time.format.DateTimeParseException: Text 'Fri Sep 30 00:00:00 IST 2022' could not be parsed at index 0
    at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
    at java.base/java.time.LocalDate.parse(LocalDate.java:428)

In DB it is saved in this format

ISODate("2022-09-29T18:30:00.000Z")

But while debugging in IDE it is coming in string format like this: "Fri Sep 30 00:00:00 IST 2022" Now I want to convert it back to instant

I tried in this way:

DateTimeFormatter DATE_FORMAT_RULE = DateTimeFormatter.ofPattern("MM/dd/yyyy");
String date = "Fri Sep 30 00:00:00 IST 2022";
Instant instant = LocalDate.parse(date, DATE_FORMAT_RULE)
                           .atStartOfDay()
                           .toInstant(ZoneOffset.UTC);
Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
Aman
  • 23
  • 3
  • Can you show how you have tried to parse that `String`? – deHaar Sep 30 '22 at 06:43
  • I think this is similar to following url https://stackoverflow.com/questions/35610597/parse-string-timestamp-to-instant-throws-unsupported-field-instantseconds – Saurabh Kumar Sep 30 '22 at 06:48
  • IDE debugging often ends up using local culture settings, because it calls `toString()` on most values that aren't built-in primitives. If you have an actual date/time value it doesn't have a built-in format. Note that ideally the database is using a date/time column, and your database driver/ORM is handling the conversion for you (that is, you shouldn't be manually formatting/parsing strings). – Clockwork-Muse Sep 30 '22 at 06:49
  • 1
    @deHaar I mentioned what I tried – Aman Sep 30 '22 at 06:53
  • The pattern does not match the one of the `String`. Your pattern cannot parse a two-digit month first because the `String` starts with an abbreviated day of week, whose abbreviation even depends on the `Locale`. However, you can try to parse it with a different pattern, but I don't think it will get you the desired result… Try `DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z uuuu", Locale.ENGLISH)` instead of your `DateTimeFormatter.ofPattern("MM/dd/yyyy")` and see the result. On my machine, it assumes IST to be Iceland Standard Time! – deHaar Sep 30 '22 at 07:00
  • Can you show your expected `Instant`? – deHaar Sep 30 '22 at 07:03
  • 1
    @deHaar It is working as expected with this pattern. Thanks – Aman Sep 30 '22 at 07:35
  • 2
    but maybe it is just wrong to get the date from database as a `String` or convert it to a `String` (but the relevant code is not included in the question) – user16320675 Sep 30 '22 at 07:54
  • 2
    Side note: The date format you use is quite dangerous for parsing. A recent change in CLDR now uses e.g. "Sept" for September in `Locale.UK`, see https://bugs.openjdk.org/browse/JDK-8256837 and https://unicode-org.github.io/cldr-staging/charts/38/delta/en.html#Months%20-%20abbreviated%20-%20Standalone. Better avoid parsing text-based date formats, if possible. – Florian Albrecht Sep 30 '22 at 09:10
  • How come you have your date and time in a string? Just don’t do that. Keep your dates and times in proper date-time objects throughout (except for presentation to the user). If you cannot retrieve an `Instant` from the database, retrieve an `OffsetDateTime` and convert simply using `yourOffsetDateTime.toInstant()`. – Ole V.V. Oct 01 '22 at 10:27

3 Answers3

2

The pattern you are using does not match the one of the String. Your pattern cannot parse a two-digit month first because the String starts with an abbreviated day of week, whose abbreviation even depends on the Locale, which you haven't specified, so it will take the system default.

However, you can try to parse it with a different pattern, but I don't think it will get you the desired result… Try DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z uuuu", Locale.ENGLISH) instead of your DateTimeFormatter.ofPattern("MM/dd/yyyy") and see the result. On my machine, it assumes IST to be Iceland Standard Time!

See this example:

public static void main(String[] args) {
    // example String
    String toBeParsed = "Fri Sep 30 00:00:00 IST 2022";
    // first formatter: tries to parse "IST" as ZONE TEXT
    DateTimeFormatter dtfZ = new DateTimeFormatterBuilder()
                                    .appendPattern("EEE MMM dd HH:mm:ss")
                                    .appendLiteral(' ')
                                    .appendZoneText(TextStyle.SHORT)
                                    .appendLiteral(' ')
                                    .appendPattern("uuuu")
                                    .toFormatter(Locale.ENGLISH);
    // second formatter: tries to parse "IST" as ZONE NAME
    DateTimeFormatter dtfz = DateTimeFormatter.ofPattern(
                                    "EEE MMM dd HH:mm:ss z uuuu",
                                    Locale.ENGLISH
                            );
    // parse to a ZonedDateTime with the first formatter
    ZonedDateTime zdt = ZonedDateTime.parse(toBeParsed, dtfZ);
    // print the result
    System.out.println("ZonedDateTime: "
                    + zdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
    // parse to a ZonedDateTime with the second formatter
    ZonedDateTime zdt2 = ZonedDateTime.parse(toBeParsed, dtfz);
    // print that, too
    System.out.println("ZonedDateTime: "
                    + zdt2.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
    // convert to an Instant
    Instant instant = zdt.toInstant();
    // print the epoch millis
    System.out.println(instant.toEpochMilli());
}

Output:

ZonedDateTime: 2022-09-30T00:00:00Z[Atlantic/Reykjavik]
ZonedDateTime: 2022-09-30T00:00:00Z[Atlantic/Reykjavik]
1664496000000

If you want the LocalDate.atStartOfDay(), you could simply extract it by calling toLocalDate() on an instance of ZonedDateTime (in case that ZonedDateTime contains any time of day different from zero hours, minutes, seconds and further down the units).

deHaar
  • 17,687
  • 10
  • 38
  • 51
2

Corresponding to 2022-09-29T18:30:00.000Z, the IST in Fri Sep 30 00:00:00 IST 2022 refers to Indian Standard Time which has a time offset of UTC+05:30. You can build a formatter using .appendZoneText(TextStyle.SHORT, Set.of(ZoneId.of("Asia/Kolkata"))) with DateTimeFormatterBuilder as shown in the demo below:

public class Main {
    public static void main(String[] args) {
        DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                .appendPattern("EEE MMM dd HH:mm:ss")
                .appendLiteral(' ')
                .appendZoneText(TextStyle.SHORT, Set.of(ZoneId.of("Asia/Kolkata")))
                .appendLiteral(' ')
                .appendPattern("uuuu")
                .toFormatter(Locale.ENGLISH);

        Instant instant = ZonedDateTime.parse("Fri Sep 30 00:00:00 IST 2022", formatter).toInstant();
        System.out.println(instant);
    }
}

Output:

2022-09-29T18:30:00Z

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

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

Works for me

        DateTimeFormatter DATE_FORMAT_RULE = DateTimeFormatter.ofPattern("E MMM dd hh:mm:ss z yyyy", Locale.US);
        String date = "Fri Sep 30 00:00:00 IST 2022";
        Instant instant2 = LocalDate.parse(date, DATE_FORMAT_RULE)
                .atStartOfDay()
                .toInstant(ZoneOffset.UTC);
viking
  • 260
  • 2
  • 10
  • 1
    This gives you the wrong result. Depending on the interpretation of `IST` the string `Fri Sep 30 00:00:00 IST 2022` corresponds to `2022-09-29T18:30:00Z` or `2022-09-29T23:00:00Z`. Your code gives neither of those, but instead `2022-09-30T00:00:00Z`. You should get the time of day and the time zone abbreviation from the string too, which `LocalDate.parse()` does not do. A `LocalDate` is a date without time of day and without time zone. – Ole V.V. Oct 01 '22 at 10:37