Varun Dhall
Varun Dhall

Reputation: 61

How do I get an Instant object with the timestamp 48962-08-06T23:16:59.000Z in Java

I have a date string which I want to parse as Instant 48962-08-06T23:16:59.000Z but unable to do as most of standard DateTimeFormatter rules are not supporting it.

Ref: https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html

Here is what I was trying to do, using my custom formatter

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .appendValue(YEAR, 5, 10, SignStyle.EXCEEDS_PAD)
            .appendLiteral('-')
            .appendValue(MONTH_OF_YEAR, 2)
            .appendLiteral('-')
            .appendValue(DAY_OF_MONTH, 2)
            .appendLiteral('T')
            .appendValue(HOUR_OF_DAY, 2).appendLiteral(':')
            .appendValue(MINUTE_OF_HOUR, 2).appendLiteral(':')
            .appendValue(SECOND_OF_MINUTE, 2)
            .appendFraction(NANO_OF_SECOND, 0, 9, true)
            .appendLiteral('Z')
            .toFormatter();
    
    Instant value = Instant.from(formatter.parse("48962-08-06T23:16:59.000Z"));

But it fails with Unable to obtain Instant from TemporalAccessor: {},ISO resolved to +48962-08-06T23:16:59 of type java.time.format.Parsed

Upvotes: 2

Views: 430

Answers (2)

Anonymous
Anonymous

Reputation: 86282

I agree with you that the nice solution is using a builder. The following one parses years with both 4 and 5 digits:

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .appendValue(ChronoField.YEAR, 4, 5, SignStyle.NOT_NEGATIVE)
            .appendPattern("-MM-dd'T'")
            .append(DateTimeFormatter.ISO_LOCAL_TIME)
            .appendOffsetId()
            .toFormatter();
    
    String dateTime = "48962-08-06T23:16:59.000Z";
    
    Instant i = formatter.parse(dateTime, Instant::from);
    
    System.out.println(i);

Output from the snippet is:

+48962-08-06T23:16:59Z

Your basic problem is that your string doesn’t conform with ISO 8601, the standard that the classes of java.time parse as their default, that is, without any explicit formatter. Years with more than 4 digits can be allowed in ISO 8601, but then a sign is required (as you can also see in the output above).

What went wrong in your code? Joachim Sauer is correct in the comment: Hardcoding Z as a literal is wrong. It’s an offset of 0 from UTC and needs to be parsed as an offset. Since your formatter didn’t parse any offset, it was unable to determine a point int time, an instant, from the parsed information. This was what your error message meant:

Unable to obtain Instant from TemporalAccessor: {},ISO resolved to +48962-08-06T23:16:59 of type java.time.format.Parsed

Upvotes: 3

deHaar
deHaar

Reputation: 18568

On my machine, the following code parses your future year:

public static void main(String[] args) {
    String dateTime = "48962-08-06T23:16:59.000Z";
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuuu-MM-dd'T'HH:mm:ss.SSSz");
    Instant instant = Instant.from(dtf.parse(dateTime));
    System.out.println(instant);
}

and outputs

+48962-08-06T23:16:59Z

I think the problem with your code is one (or both) of the lines

            .appendFraction(NANO_OF_SECOND, 0, 9, true)
            .appendLiteral('Z')

because the three digits after the dot and before the Z in the String might not be nanos of second but rather fraction of second.
And the other line might be problematic, too, but I can't really tell you why. I only know that my answer would throw an exception when the z (lower case) in the pattern is changed to a Z (upper case).

You could adjust that in your DateTimeFormatter and try again, might work.

Upvotes: 4

Related Questions