Search code examples
javadatetimejava-8datetime-formatjava-time

UnsupportedTemporalTypeException when formatting Instant to String


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)
    ...

Solution

  • 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