1

How do I convert the datetime that is passed as string 2018-08-10T18:25:00.000+0000 to a Instant? I tried the below and it did not work.

 public static Instant toInstant(final String timeStr) {
    if (StringUtils.isBlank(timeStr)) {
        throw new IllegalArgumentException("Invalid date time value passed [" + timeStr + "]");
    }

    try {
        return LocalDate.parse(timeStr).atStartOfDay().toInstant(ZoneOffset.UTC);
    } catch (Exception e) {
        try {
            return LocalDateTime.parse(timeStr).toInstant(ZoneOffset.UTC);
        } catch (Exception e1) {
            try {
                return ZonedDateTime.parse(timeStr).toInstant();
            } catch (Exception e2) {
                try {
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                    return LocalDateTime.parse(timeStr, formatter).toInstant(ZoneOffset.UTC);
                } catch (Exception e3) {
                    try {
                        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
                        return LocalDateTime.parse(timeStr, formatter).toInstant(ZoneOffset.UTC);
                    } catch (Exception e4) {
                        try {
                            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS");
                            return LocalDateTime.parse(timeStr, formatter).toInstant(ZoneOffset.UTC);
                        } catch (Exception e5) {
                        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
                            return LocalDateTime.parse(timeStr, formatter).toInstant(ZoneOffset.UTC);
                        } finally {
                            throw new IllegalArgumentException("Incorrect date time value passed [" + timeStr + "]");
                        }
                    }
                }
            }
        }
    }
}
Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
serah
  • 2,057
  • 7
  • 36
  • 56
  • 1
    What's wrong with a simple `OffsetDateTime.parse(...).toInstant()`? Why the many tries? – Seelenvirtuose Oct 11 '21 at 16:49
  • "2018-08-10T18:25:00.000+0000" is not ISO-conformant, but "2018-08-10T18:25:00.000+00:00" is. (Note the added colon.) If you use the correct format, you can use `Instant instant = Instant.parse("2018-08-10T18:25:00.000+00:00");` – k314159 Oct 11 '21 at 16:49
  • @Seelenvirtuose `Instant.parse` is even shorter. – k314159 Oct 11 '21 at 16:51
  • 1
    @k314159 Indeed the string conforms to ISO 8601. Funnily the one-arg `OffsetDateTime.parse(CharSequence)` does not accept it. See for example [Why can't OffsetDateTime parse '2016-08-24T18:38:05.507+0000' in Java 8](https://stackoverflow.com/questions/39133828/why-cant-offsetdatetime-parse-2016-08-24t183805-5070000-in-java-8) – Ole V.V. Oct 12 '21 at 06:40

3 Answers3

1

You can use OffsetDateTime with DateTimeFormatter. Something like this,

public static Instant toInstant(final String timeStr) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
    OffsetDateTime dateTime = OffsetDateTime.parse(timeStr, formatter);
    return dateTime.toInstant();
}
ray
  • 1,512
  • 4
  • 11
1

Your string, 2018-08-10T18:25:00.000+0000 has a timezone offset of +0000 hours and therefore, you should parse it to OffsetDateTime which can be converted into Instant.

Demo:

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

public class Main {
    public static void main(String args[]) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSZ", Locale.ENGLISH);
        OffsetDateTime odt = OffsetDateTime.parse("2018-08-10T18:25:00.000+0000", dtf);
        Instant instant = odt.toInstant();
        System.out.println(instant);
    }
}

Output:

2018-08-10T18:25:00Z

ONLINE DEMO

The DateTimeFormatter used in the above solution will work only for a fixed number of digits specified in the pattern e.g. only 3 digits in the fraction-of-second. A better DateTimeFormatter can be built using DateTimeFormatterBuilder as shown in the following demo:

import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Locale;

public class Main {
    public static void main(String args[]) {
        DateTimeFormatter dtf = new DateTimeFormatterBuilder()
                                .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
                                .appendPattern("Z")
                                .toFormatter(Locale.ENGLISH);
        OffsetDateTime odt = OffsetDateTime.parse("2018-08-10T18:25:00.000+0000", dtf);
        Instant instant = odt.toInstant();
        System.out.println(instant);
    }
}

Output:

2018-08-10T18:25:00Z

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
0

Your trouble is here:

        } finally {
            throw new IllegalArgumentException("Incorrect date time value passed [" + timeStr + "]");
        }

Your parsing is successful in these lines (but may give an incorrect result):

            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
            return LocalDateTime.parse(timeStr, formatter).toInstant(ZoneOffset.UTC);

After you have successfully parsed your string, in your finally block you are throwing an exception. So the caller does not receive the result and instead gets an exception and will have to think that parsing or conversion failed.

An incorrect result? Your parsing into LocalDateTime throws away the UTC offset in the string, +0000. Next your conversion to Instant assumes UTC, which in this case happens to agree with the string. If the offset in the string had been anyting else than +0000 (for example, +0100), you will get an incorrect Instant.

The other answers show correct ways of converting your string to Instant.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161