Pattern YYYY-MM-DD'T'hh:mm'Z' is wrong:

  • YYYY - week-based-year       wrong: use uuuu year
  • MM - month-of-year
  • DD - day-of-year       wrong: use dd day-of-month
  • hh - clock-hour-of-am-pm (1-12)       without AM/PM you probably want HH hour-of-day (0-23)
  • mm - minute-of-hour

It's weird, because you even referenced a link that had the right pattern characters. Unless of course you thought upper- vs lower-case didn't matter, but if so, how did you think MM (month) vs mm (minute) worked?

You might want to actually read the documentation.

Answer from Andreas on Stack Overflow
🌐
Baeldung
baeldung.com › home › java › java dates › format instant to string in java
Format Instant to String in Java | Baeldung
January 8, 2024 - Fortunately for us, Java 8 introduced the DateTimeFormatter class to uniformly format dates and times. Basically, DateTimeFormatter provides the format() method to do the job. Simply put, DateTimeFormatter requires a time zone to format an instant.
Discussions

java - Why is Instant.now() sometimes formatted differently? - Stack Overflow
The format used is the same as DateTimeFormatter.ISO_INSTANT. More on stackoverflow.com
🌐 stackoverflow.com
Has the precision of Instant.now changed in Java 17?
It has happened in Java 15: https://bugs.openjdk.org/browse/JDK-8242504 More on reddit.com
🌐 r/java
31
72
September 13, 2024
How to create Java time instant from pattern? - Stack Overflow
Contrary to what you've shown the parse method of java.util.Instant does not take a DateTimeFormatter. Instead you have to do FMT.parse("9999-31-12", Instant::from). As the author could you explain why Instant is different to the other classes, e.g. LocalDateTime, in this respect? 2017-01-24T12:47:18.703Z+00:00 ... Originally, Instant did not work with DateTimeFormatter at all. This was changed during development, but the method you refer to was not added. That said, because many formatters ... More on stackoverflow.com
🌐 stackoverflow.com
java.time.DateTimeFormatter : Need ISO_INSTANT that always renders milliseconds - Stack Overflow
I'm trying to cleanup a mix of various code around datetime management to only Java 8 java.time namespace. Right now I have a small issue with the default DateTimeFormatter for Instant. The DateTimeFormatter.ISO_INSTANT formatter only shows milliseconds when they are not equal to zero. More on stackoverflow.com
🌐 stackoverflow.com
🌐
Oracle
docs.oracle.com › javase › 8 › docs › api › java › time › Instant.html
Instant (Java Platform SE 8 )
2 weeks ago - Java™ Platform Standard Ed. 8 ... public final class Instant extends Object implements Temporal, TemporalAdjuster, Comparable<Instant>, Serializable
🌐
Medium
medium.com › @AlexanderObregon › javas-instant-now-method-explained-5403bac7ec1e
Java’s Instant.now() Method Explained | Medium
September 13, 2024 - When Instant.now() is called, it returns the current timestamp in UTC (Coordinated Universal Time). This timestamp is represented as an Instant object, which stores the time as seconds and nanoseconds from the standard Java epoch (1970-01-0...
🌐
Spring
docs.spring.io › spring-framework › docs › 5.1.0.RC3_to_5.1.0.RELEASE › Spring Framework 5.1.0.RELEASE › org › springframework › format › datetime › standard › InstantFormatter.html
InstantFormatter
Formatter<java.time.Instant>, Parser<java.time.Instant>, Printer<java.time.Instant> public class InstantFormatter extends java.lang.Object implements Formatter<java.time.Instant> Formatter implementation for a JSR-310 Instant, following JSR-310's parsing rules for an Instant (that is, not using a configurable DateTimeFormatter): accepting the default ISO_INSTANT format as well as RFC_1123_DATE_TIME (which is commonly used for HTTP date header values), as of Spring 4.3.
Find elsewhere
🌐
GeeksforGeeks
geeksforgeeks.org › java › instant-tostring-method-in-java-with-examples
Instant toString() method in Java with Examples - GeeksforGeeks
November 28, 2018 - The toString() method of Instant class returns string representation of this instant using ISO-8601 representation and format used is the same as DateTimeFormatter.ISO_INSTANT. Syntax: public String toString() Returns: This method returns an ...
🌐
Oracle
docs.oracle.com › javase › 8 › docs › api › java › time › format › DateTimeFormatter.html
DateTimeFormatter (Java Platform SE 8 )
2 weeks ago - This returns an immutable formatter capable of formatting and parsing the ISO-8601 instant format. When formatting, the second-of-minute is always output. The nano-of-second outputs zero, three, six or nine digits digits as necessary. When parsing, time to at least the seconds field is required.
🌐
Java2Blog
java2blog.com › home › core java › java 8 › how to format instant to string in java
How to Format Instant to String in Java - Java2Blog
November 21, 2023 - The DateTimeFormatter approach is the most flexible and aligns with the modern Java Date-Time API, making it the preferred choice. The built-in toString() method of Instant is convenient for standard ISO-8601 formats, while the SimpleDateFormat approach is useful for legacy applications.
🌐
W3Schools
w3schools.com › java › java_date.asp
Java Date and Time
assert abstract boolean break byte case catch char class continue default do double else enum exports extends final finally float for if implements import instanceof int interface long module native new package private protected public return requires short static super switch synchronized this throw throws transient try var void volatile while Java String Methods · charAt() codePointAt() codePointBefore() codePointCount() compareTo() compareToIgnoreCase() concat() contains() contentEquals() copyValueOf() endsWith() equals() equalsIgnoreCase() format() getBytes() getChars() hashCode() indexOf() isEmpty() join() lastIndexOf() length() matches() offsetByCodePoints() regionMatches() replace() replaceAll() replaceFirst() split() startsWith() subSequence() substring() toCharArray() toLowerCase() toString() toUpperCase() trim() valueOf() Java Math Methods
🌐
PriorityQueue
nkamphoa.com › home › instant class in java
Instant Class in Java
January 10, 2026 - By default, the Instant is formatted using the ISO-8601 date format. The Instant class does not have fields like year, month, etc.
🌐
Reddit
reddit.com › r/java › has the precision of instant.now changed in java 17?
r/java on Reddit: Has the precision of Instant.now changed in Java 17?
September 13, 2024 -

I'm just upgrading a project from Java 11 to Java 21 and found that Instant.now() has greater precision now since Java 17. Previously, it was microseconds and now it is nanoseconds.

This is reasonable as the Javadoc does say the precision is system dependent. Unfortunately, this makes the upgrade less trivial for us as this extra precision causes issues with some databases, and some clients of our API.

I can't find anything in the release notes and want to confirm that:

  • This is actually a change due to my upgrade and not some other factor I haven't realized

  • There isn't a flag that I can use to activate the previous behaviour

I'm a bit paranoid because I don't see why this wouldn't have occurred with Java 11 also but it seems to me that upgrading past Java 17 reliably reproduces the behaviour, on the same exact system.

Otherwise, I think I will need to wrap this method and truncate it in order to get back the previous behavior as I cannot update all of the clients in a backwards compatible way.

Top answer
1 of 4
98

The string "9999-12-31" only contains information about a date. It does not contain any information about the time-of-day or offset. As such, there is insufficient information to create an Instant. (Other date and time libraries are more lenient, but java.time avoids defaulting these values)

Your first choice is to use a LocalDate instead of an `Instant:

LocalDate date = LocalDate.parse("9999-12-31");

Your second choice is to post process the date to convert it to an instant, which requires a time-zone, here chosen to be Paris:

LocalDate date = LocalDate.parse("9999-12-31");
Instant instant = date.atStartOfDay(ZoneId.of("Europe/Paris")).toInstant();

Your third choice is to add the time-zone to the formatter, and default the time-of-day:

static final DateTimeFormatter FMT = new DateTimeFormatterBuilder()
    .appendPattern("yyyy-MM-dd")
    .parseDefaulting(ChronoField.NANO_OF_DAY, 0)
    .toFormatter()
    .withZone(ZoneId.of("Europe/Paris"));
Instant instant = FMT.parse("9999-31-12", Instant::from);

(If this doesn't work, ensure you have the latest JDK 8 release as a bug was fixed in this area).

It is worth noting that none of these possibilities use TemporalAccessor directly, because that type is a low-level framework interface, not one for most application developers to use.

2 of 4
25

The problem isn't the fact that you are using the year 9999. The Instant.MAX field evaluates to the timestamp 1000000000-12-31T23:59:59.999999999Z, so 9999 as a year is fine.

Dealing with TemporalAccessors instead of the more semantically rich types like LocalDateTime or ZonedDateTime is like using a Map to model an object and its properties instead of writing a class -- you have to assure that the value has the fields (like seconds, nanoseconds, etc) that are expected by something receiving it, rather than depending on formally declared operations in a higher level class to prevent dependencies from going unmet.

In your case it is likely that the temporal accessor contained the parsed date fields it was given, but didn't have a "seconds" field that the Instant needed. It is best to use the more semantically rich types like LocalDateTime in most instances.

Since you only have date fields, you should parse it as a date, then add the time fields before converting it to an Instant. Here is one way, using LocalDate to parse the date:

LocalDate localDate = LocalDate.parse("2016-04-17");
LocalDateTime localDateTime = localDate.atStartOfDay();
Instant instant = localDateTime.toInstant(ZoneOffset.UTC);
🌐
DigitalOcean
digitalocean.com › community › tutorials › java-8-date-localdate-localdatetime-instant
Java 8 Date: LocalDate, LocalDateTime, Instant Guide | DigitalOcean
August 3, 2022 - Default format of LocalDate=2014-04-28 28::Apr::2014 20140428 Default format of LocalDateTime=2014-04-28T16:25:49.341 28::Apr::2014 16::25::49 20140428 Default format of Instant=2014-04-28T23:25:49.342Z Default format after parsing = 2014-04-27T21:39:48 · Legacy Date/Time classes are used in almost all the applications, so having backward compatibility is a must. That’s why there are several utility methods through which we can convert Legacy classes to new classes and vice versa. package com.journaldev.java8.time; import java.time.Instant; import java.time.LocalDateTime; import java.time.Z
Top answer
1 of 2
39

OK, I looked at the the source code and it's pretty straightforward:

DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendInstant(3).toFormatter();

I hope it works for all scenarios, and it can help someone else. Don't hesitate to add a better/cleaner answer.

Just to explain where it comes from, in the JDK's code,

ISO_INSTANT is defined like this:

public static final DateTimeFormatter ISO_INSTANT;
static {
    ISO_INSTANT = new DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .appendInstant()
            .toFormatter(ResolverStyle.STRICT, null);
}

And DateTimeFormatterBuilder::appendInstant is declared as:

public DateTimeFormatterBuilder appendInstant() {
    appendInternal(new InstantPrinterParser(-2));
    return this;
}

And the constructor InstantPrinterParser signature is:

InstantPrinterParser(int fractionalDigits)
2 of 2
8

The accepted Answer by Florent is correct and good.

I just want to add some clarification.

The mentioned formatter, DateTimeFormatter.ISO_INSTANT, is default only for the Instant class. Other classes such as OffsetDateTime and ZonedDateTime may use other formatters by default.

The java.time classes offer a resolution up to nanosecond, much finer granularity than milliseconds. That means up to 9 digits in the decimal fraction rather than merely 3 digits.

The behavior of DateTimeFormatter.ISO_INSTANT varies by the number of digits in the decimal fraction. As the doc says (emphasis mine):

When formatting, the second-of-minute is always output. The nano-of-second outputs zero, three, six or nine digits as necessary.

So depending on the data value contained within the Instant object, you may see any of these outputs:

2011-12-03T10:15:30Z

2011-12-03T10:15:30.100Z

2011-12-03T10:15:30.120Z

2011-12-03T10:15:30.123Z

2011-12-03T10:15:30.123400Z

2011-12-03T10:15:30.123456Z

2011-12-03T10:15:30.123456780Z

2011-12-03T10:15:30.123456789Z

The Instant class is meant to be the basic building block of java.time. Use it frequently for data passing, data storage, and data exchange. When generating String representations of the data for presentation to users, use OffsetDateTime or ZonedDateTime.

🌐
Medium
medium.com › @AlexanderObregon › javas-instant-ofepochmilli-method-explained-cb1aa882a478
Java’s Instant.ofEpochMilli() Method Explained | Medium
October 17, 2024 - The Instant class, part of the java.time package, represents a specific point in time, modeled as the number of nanoseconds since the epoch. It is used to deal with precise moments in time, unlike Date or Calendar, which focus on human-readable ...
🌐
Baeldung
baeldung.com › home › json › jackson › set format for instant using objectmapper
Set Format for Instant Using ObjectMapper | Baeldung
June 17, 2024 - With serialization covered, let’s ensure we can deserialize objects with this specific format. For deserialization, we’ll follow a similar route by extending JsonDeserializer: public class CustomInstantDeserializer extends JsonDeserializer<Instant> { @Override public Instant deserialize(JsonParser json, DeserializationContext context) throws IOException { // ...
🌐
Coderanch
coderanch.com › t › 664480 › java › java-time-Instant-local-time
java.time.Instant not local time. (Features new in Java 8 forum at Coderanch)
April 14, 2016 - Instant is UTC I think (can't check as I don't have Java 8 here). If you want the local time then there's a LocalTime class. ... A string representation of this instant using ISO-8601 representation. The format used is the same as DateTimeFormatter.ISO_INSTANT.