将Instant格式化为String


226

我正在尝试使用新的Java 8 time-api和模式将Instant格式化为String:

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

使用上面的代码,我得到一个异常,该异常抱怨一个不受支持的字段:

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

Answers:


309

时区

要格式化Instant一个时区。没有时区,格式化程序将不知道如何将即时转换为人类日期时间字段,因此会引发异常。

可以使用将时区直接添加到格式化程序withZone()

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

产生字串

现在,使用该格式化程序生成Instant的String表示形式。

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

转储到控制台。

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

运行时。

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

50
谢谢!!顺便说一句,指向“年份”的“不受支持的字段”异常过时。也许应该检测到这种情况,并抛出直接指向Instant中缺少的区域ID的异常!
davidbak

1
更奇怪的是,如果包含.withZone(例如.withZone(ZoneId.of(“ Z”)))并设置LocalDateTime的格式,则该区域为IGNORED!因此,只要包含.withZone(),同一格式器就可以用于Instant和LocalDateTime,而不会影响后者的显示时间。
格伦

1
为什么很难接受Instant具有一个GMT的TimeZone的事实?
Koray Tugay

1
@KorayTugay因为书呆子的“ Instant已经是GMT”的注释可能是正确的,但是在面对引发的异常跟踪时它们却无济于事,因为格式化Instant 而不指定时区是行不通的。如果格式化程序默认为GMT,那会很好,但是,哦。
Ti Strga,

现在,您可以使用以下yyyy-MM-dd hh:mm:ss格式:DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss").withZone(ZoneId.of("Europe/Paris"));
WesternGun

38
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()));

}

3
尽管此代码可以回答问题,但提供有关如何以及为什么解决问题的其他上下文将提高答案的长期价值。
亚历山大

1
尽管此代码段可以解决问题,但提供说明确实有助于提高您的帖子质量。请记住,您将来会为读者回答这个问题,而这些人可能不知道您提出代码建议的原因。
罗萨里奥·佩雷拉·费尔南德斯

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

这使您不必转换为UTC。但是,某些其他语言的时间框架可能不支持毫秒,因此您应该这样做

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

您所说的“其他语言的时间框架”是什么意思?ISO_INSTANT.format()是否会自动截断为秒?

一些框架期望仅花费时间达到几秒钟,因为它们不遵循完整的ISO约定,并且在输入字符串中包含毫秒时会中断。
阿基米德·特拉哈诺

21

Instant类不包含区的信息,它只存储毫秒时间戳记UNIX时代,即1070年1月1日从UTC。因此,格式化程序无法打印日期,因为日期始终是针对特定时区打印的。您应该将时区设置为格式化程序,这样就可以了,就像这样:

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

4

或者,如果您仍然想使用从模式创建的格式化程序,则可以使用LocalDateTime代替Instant:

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

4

即时消息已经采用UTC,并且已经具有默认日期格式yyyy-MM-dd。如果您对此感到满意,并且不想弄乱时区或格式,也toString()可以:

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


不需要T和Z吗?(Z表示该日期为世界标准时间。Z代表“ Zulu”(又名“零时偏移”),又名UTC):

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


想要毫秒而不是纳秒?(因此您可以将其放入sql查询中):

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

等等


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

我相信这可能会有所帮助,您可能需要使用某种本地日期变体而不是即时

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.