Java 8:将文件时间(从1970年的毫秒数)转换为RFC 1123格式

时间:2015-07-20 19:22:49

标签: java java-8

这似乎应该很简单,但到目前为止我没有尝试过工作。基本上我想将从1970年(通常)的文件时间(以毫秒为单位)转换为TemporalAccessor,然后转换为RFC 1123格式化的字符串。但是,虽然我可以获得编译的示例,但我得到运行时错误。例如:

// Just using 0 milliseconds time for quick and easy test
System.out.println(java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME.format(
                FileTime.from(0, TimeUnit.MILLISECONDS).toInstant()));

结果

  

线程中的异常" main" java.time.temporal.UnsupportedTemporalTypeException:       不支持的字段:DayOfMonth

我尝试过使用不同类别(Instant,LocalTime,Date)的一些变体,但我得到了相同的结果。

这样做的正确方法是什么?

更新: 最初的问题已在技术上得到解答,我意识到我需要更加具体。我已经成功了#39;我自己将毫秒转换为TemporalAccessor,但它看起来并不像这个对象处于可用状态。我试图用它来做我真正需要的东西时遇到了运行时错误,这让我相信我没有正确地创建它。那东西不见了。 RFC 1123格式化程序中存在错误或存在错误。

更新2: 感谢Sleafar发布了一个有效的答案。

使用他的例子我做的略有不同,因为出于某种原因我真的想要一个完整的' TemporalAccessor做的东西。这是一个有效的例子:

TemporalAccessor time = ZonedDateTime.ofInstant(Instant.ofEpochMilli(0),
ZoneId.systemDefault());
System.out.println(
        java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME.format(time));

3 个答案:

答案 0 :(得分:8)

Instant类型不包含时区信息。您可以为格式化程序定义时区,如下所示:

System.out.println(java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME
    .withZone(ZoneId.systemDefault()).format( FileTime.from(0, TimeUnit.MILLISECONDS).toInstant()));

编辑:

实际上有理由让格式化程序没有指定的时区,以及表示类的日期/时间。请考虑以下示例:

ZoneId ect = ZoneId.of(ZoneId.SHORT_IDS.get("ECT"));

DateTimeFormatter f1 = DateTimeFormatter.RFC_1123_DATE_TIME;
DateTimeFormatter f2 = f1.withZone(ect);
DateTimeFormatter f3 = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
DateTimeFormatter f4 = f3.withZone(ect);

LocalDateTime ldt = LocalDateTime.of(2015, 07, 21, 0, 0, 0, 0);
ZonedDateTime zdt = ZonedDateTime.of(ldt, ect);
Instant ins = zdt.toInstant();

System.out.println(f1.format(ins)); // throws exception (1)
System.out.println(f2.format(ins)); // Tue, 21 Jul 2015 00:00:00 +0200
System.out.println(f3.format(ins)); // throws exception (2)
System.out.println(f4.format(ins)); // 2015-07-21T00:00:00

System.out.println(f1.format(zdt)); // Tue, 21 Jul 2015 00:00:00 +0200
System.out.println(f2.format(zdt)); // Tue, 21 Jul 2015 00:00:00 +0200
System.out.println(f3.format(zdt)); // 2015-07-21T00:00:00
System.out.println(f4.format(zdt)); // 2015-07-21T00:00:00

System.out.println(f1.format(ldt)); // throws exception (3)
System.out.println(f2.format(ldt)); // throws exception (4)
System.out.println(f3.format(ldt)); // 2015-07-21T00:00:00
System.out.println(f4.format(ldt)); // 2015-07-21T00:00:00

ZoneId hst = ZoneId.of(ZoneId.SHORT_IDS.get("HST"));
ZonedDateTime zdt2 = ZonedDateTime.of(ldt, hst);

System.out.println(f1.format(zdt2)); // Tue, 21 Jul 2015 00:00:00 -1000
System.out.println(f2.format(zdt2)); // Tue, 21 Jul 2015 12:00:00 +0200
System.out.println(f3.format(zdt2)); // 2015-07-21T00:00:00
System.out.println(f4.format(zdt2)); // 2015-07-21T12:00:00
  • Instant代表实际的时间点,而不是指特定的位置,因此没有时区。引发异常(1)和(2)是因为要表示格式化程序需要时区以使输出对人类可读的特定时间点。
  • ZonedDateTime表示也分配给特定时区的实际时间点。没有任何问题可以格式化它们,但请考虑最后一个例子。如果在格式化程序中设置时区,则可能会得到不同的结果。
  • LocalDateTime并不代表实际的时间点。您甚至可以在某些时区指定一个无效的值,例如在夏令时的情况下将时钟向前推进1小时。要获得真正的时间点,您必须将其与时区结合(如上例所示)。引发了异常(3)和(4),因为格式化程序想要打印时区值,该值不存在于此类型中。

我无法说明为什么设计人员选择在运行时而不是编译时发现所描述的问题。也许它会使类层次结构太复杂。

答案 1 :(得分:1)

自1970年以来的毫秒被称为"纪元时间",而Instant具有静态方法Instant.ofEpochMilli(long)以支持从long毫秒数的创建。概念上,Instant代表标准Java纪元"中的单个时刻(long秒+ int纳秒),因此将文件时间表示为Instant是正确的JSR-310方法它

FileTime也有一个fromMillis(long)静态方法用于相同目的。

在这种情况下,转换不是问题 - 正如Sleafar首先确定的那样缺少时区,正如您编辑过的问题所反映的那样。

答案 2 :(得分:1)

转换为Instant成功没有问题。问题是格式化程序。使用ISO_INSTANT格式化程序而不是RFC_1123_DATE_TIME然后你应该去:

        inst = Instant.now();
        System.out.println(java.time.format.DateTimeFormatter.ISO_INSTANT
                           .format( inst ) );

- > 2015-07-20T21:11:53.001Z

如果您真的想要使用RFC_1123格式,则必须声明时区。

将其附加到格式化程序:

        System.out.println(java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME
                           .withZone( ZoneOffset.UTC )
                           .format( inst ) );

或将Instant转换为ZonedDateTime:

        ZonedDateTime zdt = ZonedDateTime.ofInstant( inst, ZoneOffset.UTC );
        System.out.println(java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME
                           .format( zdt ) );

- >星期一,2015年7月20日21:11:53 GMT