添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
留胡子的扁豆  ·  sql ...·  2 天前    · 
要出家的小熊猫  ·  Java ...·  19 小时前    · 
打篮球的领带  ·  sklearn.manifold.Local ...·  5 月前    · 
聪明伶俐的小刀  ·  SQLite文本字符集·  6 月前    · 
耍酷的书签  ·  maven导入Gson_class_bric ...·  1 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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)

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
                Thank you!!  BTW the exception "unsupported field" pointing to, e.g., year, is spectacularly obtuse.  Maybe this situation should be detected and an exception pointing directly to the missing zone id in the Instant should be thrown!
– davidbak
                Oct 22, 2015 at 18:06
                More bizarrely, if you include .withZone (e.g., .withZone(ZoneId.of("Z")) ) and format a LocalDateTime, the zone is IGNORED! So as long as .withZone() is included, the same formatter can be used both for Instant and for LocalDateTime, without affecting the time shown for the latter.
– Glenn
                Feb 5, 2018 at 18:49
                @KorayTugay Because while pedantic "Instant is already GMT" comments might be true, they're far from helpful when facing an exception trace thrown because formatting an Instant without specifying a timezone does not work.  It would have been nice if the formatter defaulted to GMT, but oh well.
– Ti Strga
                Aug 29, 2019 at 22:02
                Now this gives you yyyy-MM-dd hh:mm:ss format: DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss").withZone(ZoneId.of("Europe/Paris"));
– WesternGun
                Mar 25, 2020 at 15:03
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()));
                While this code may answer the question, providing additional context regarding how and why it solves the problem would improve the answer's long-term value.
– Alexander
                Feb 3, 2018 at 16:36
                While this code snippet may solve the question, including an explanation really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion.
– Rosário Pereira Fernandes
                Feb 3, 2018 at 18:48

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))
                What do you mean by "some other language's time frameworks"? Will ISO_INSTANT.format() automatically truncate to seconds?
– Guangtong Shen
                Apr 18, 2019 at 0:09
                Some frameworks expect only the time to go up to the seconds because they don't follow the full ISO convention and break when there's milliseconds as part of the input string.
– Archimedes Trajano
                Apr 18, 2019 at 17:03

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");

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

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)
                Exception java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra
– agilob
                Nov 4, 2020 at 21:56
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