Unsupportedtemporaltypeexception When Formatting Instant to String

UnsupportedTemporalTypeException when formatting Instant to String

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

Formatting Java Instant to YYYYMMdd adds an extra year?

You want lowercase y -

        System.out.println(
DateTimeFormatter.ofPattern("yyyyMMdd")
.withZone(ZoneId.of("UTC"))
.format(Instant.parse("2020-12-31T08:00:00Z"))
);

Unsupported field: Year when formatting an instant to Date ISO

To format an Instant a time-zone is required.

 String input = "20161012235959.0Z";
DateTimeFormatter f = DateTimeFormatter
.ofPattern ( "uuuuMMddHHmmss.SX" )
.withLocale( Locale.FRANCE )
.withZone( ZoneId.of("UTC"));
OffsetDateTime odt = OffsetDateTime.parse ( input , f );
Instant instant = odt.toInstant ();

System.out.println(input);
System.out.print(f.format(instant));

Formatting Instant to String with specific pattern

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.

java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: OffsetSeconds

use OffsetDateTime which has offset of the timezone and truncate it to seconds

A date-time with an offset from UTC/Greenwich in the ISO-8601 calendar system, such as 2007-12-03T10:15:30+01:00.

OffsetDateTime offsetDateTime = OffsetDateTime.now(ZoneId.of("Europe/Paris"));

offsetDateTime.truncatedTo(ChronoUnit.SECONDS).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); //2020-12-29T18:28:44+01:00

If you want a custom format the build it using DateTimeFormatterBuilder

OffsetDateTime offsetDateTime = OffsetDateTime.now(ZoneOffset.UTC);

DateTimeFormatter dateTimeFormatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.appendOffset("+HHMM", "+0000")
.toFormatter();
offsetDateTime.truncatedTo(ChronoUnit.SECONDS).format(dateTimeFormatter); //2020-12-29T17:36:51+0000

Parse String timestamp to Instant throws Unsupported field: InstantSeconds

Here is how to get an Instant with a default time zone. Your String can not be parsed straight to Instant because timezone is missing. So you can always get the default one

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

String timestamp = "2016-02-16 11:00:02";
TemporalAccessor temporalAccessor = formatter.parse(timestamp);
LocalDateTime localDateTime = LocalDateTime.from(temporalAccessor);
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.systemDefault());
Instant result = Instant.from(zonedDateTime);

How to get yyyy-MM-dd from an Instant object in java 8.?

I suggest to cast to a LocalDateTime and then use DateTimeFormatter like

LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
String result = ldt.format(DateTimeFormatter.ISO_LOCAL_DATE);

You can find formatter list here, or use your own pattern

Other ways

As @Holger said in the comments, DateTimeFormatter.ISO_LOCAL_DATE.withZone(ZoneOffset.UTC) produces a formatter that can directly format the Instant and can be shared and reused to format a lot of instants.

static final DateTimeFormatter INSTANT_FORMATTER
= DateTimeFormatter.ISO_LOCAL_DATE.withZone(ZoneOffset.UTC);

Use like

    String result = INSTANT_FORMATTER .format(instant);

@Ole V.V. mentioned that converting to LocalDateTime as in my first snippet throws away the information about which point in time we had. We can keep that information with us when instead we convert to ZonedDateTime or OffsetDateTime. If you want to interpret the date in UTC (as in the previous examples), for example:

    String result = instant.atOffset(ZoneOffset.UTC).format(DateTimeFormatter.ISO_LOCAL_DATE);

This makes it more explicit that the operation is dependent on the choice of UTC for interpretation.



Related Topics



Leave a reply



Submit