UnsupportedTemporalTypeException when formatting Instant to String

JavaDatetimeJava 8Datetime FormatJava Time

Java Problem Overview


I'm trying to format an Instant to a String using the new Java 8 Date and Time API and the following pattern:

Instant instant = ...;
String out = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(instant);

Using the code above I get an exception which complains about an unsupported field:

java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra
	at java.time.Instant.getLong(Instant.java:608)
	at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)
    ...

Java Solutions


Solution 1 - Java

Time Zone

To format an Instant a time-zone is required. Without a time-zone, the formatter does not know how to convert the instant to human date-time fields, and therefore throws an exception.

The time-zone can be added directly to the formatter using withZone().

DateTimeFormatter formatter =
    DateTimeFormatter.ofLocalizedDateTime( FormatStyle.SHORT )
                     .withLocale( Locale.UK )
                     .withZone( ZoneId.systemDefault() );

If you specifically want an ISO-8601 format with no explicit time-zone (as the OP asked), with the time-zone implicitly UTC, you need

DateTimeFormatter.ISO_LOCAL_DATE_TIME.withZone(ZoneId.from(ZoneOffset.UTC))

Generating String

Now use that formatter to generate the String representation of your Instant.

Instant instant = Instant.now();
String output = formatter.format( instant );

Dump to console.

System.out.println("formatter: " + formatter + " with zone: " + formatter.getZone() + " and Locale: " + formatter.getLocale() );
System.out.println("instant: " + instant );
System.out.println("output: " + output );

When run.

formatter: Localized(SHORT,SHORT) with zone: US/Pacific and Locale: en_GB
instant: 2015-06-02T21:34:33.616Z
output: 02/06/15 14:34

Solution 2 - Java

public static void main(String[] args) {

    DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
            .withZone(ZoneId.systemDefault());

    System.out.println(DATE_TIME_FORMATTER.format(new Date().toInstant()));

}

Solution 3 - Java

DateTimeFormatter.ISO_INSTANT.format(Instant.now())

This saves you from having to convert to UTC. However, some other language's time frameworks may not support the milliseconds so you should do

DateTimeFormatter.ISO_INSTANT.format(Instant.now().truncatedTo(ChronoUnit.SECONDS))

Solution 4 - Java

The Instant class doesn't contain Zone information, it only stores timestamp in milliseconds from UNIX epoch, i.e. 1 Jan 1070 from UTC. So, formatter can't print a date because date always printed for concrete time zone. You should set time zone to formatter and all will be fine, like this :

Instant instant = Instant.ofEpochMilli(92554380000L);
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withLocale(Locale.UK).withZone(ZoneOffset.UTC);
assert formatter.format(instant).equals("07/12/72 05:33");
assert instant.toString().equals("1972-12-07T05:33:00Z");

Solution 5 - Java

Instants are already in UTC and already have a default date format of yyyy-MM-dd. If you're happy with that and don't want to mess with time zones or formatting, you could also toString() it:

Instant instant = Instant.now();
instant.toString()
output: 2020-02-06T18:01:55.648475Z


Don't want the T and Z? (Z indicates this date is UTC. Z stands for "Zulu" aka "Zero hour offset" aka UTC):

instant.toString().replaceAll("[TZ]", " ")
output: 2020-02-06 18:01:55.663763


Want milliseconds instead of nanoseconds? (So you can plop it into a sql query):

instant.truncatedTo(ChronoUnit.MILLIS).toString().replaceAll("[TZ]", " ")
output: 2020-02-06 18:01:55.664

etc.

Solution 6 - Java

Or if you still want to use formatter created from pattern you can just use LocalDateTime instead of Instant:

LocalDateTime datetime = LocalDateTime.now();
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(datetime)

Solution 7 - Java

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
String text = date.toString(formatter);
LocalDate date = LocalDate.parse(text, formatter);

I believe this might help, you may need to use some sort of localdate variation instead of instant

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDagView Question on Stackoverflow
Solution 1 - JavaJodaStephenView Answer on Stackoverflow
Solution 2 - Java二叉树View Answer on Stackoverflow
Solution 3 - JavaArchimedes TrajanoView Answer on Stackoverflow
Solution 4 - JavaSergey PonomarevView Answer on Stackoverflow
Solution 5 - Javacs_pupilView Answer on Stackoverflow
Solution 6 - JavaNik.exeView Answer on Stackoverflow
Solution 7 - Javauser3255780View Answer on Stackoverflow