Java 8: Convert file time (milliseconds from 1970) to RFC 1123 format

后端 未结 3 1722
北恋
北恋 2021-01-06 00:45

This seems like it should be simple, but so far nothing I try is working. Basically I want to convert a file time in milliseconds from 1970 (the usual) to a TemporalAccessor

相关标签:
3条回答
  • 2021-01-06 01:18

    Milliseconds since 1970 is known as "epoch time", and Instant has the static method Instant.ofEpochMilli(long) to support creation from a long number of milliseconds. Conceptually Instant represents a single moment (long seconds + int nanoseconds) in "the standard Java epoch", so representing file time as an Instant is the correct JSR-310 way to do it.

    FileTime also has a fromMillis(long) static method for the same purpose.

    In this case, the conversion wasn't the problem—it was the lack of timezone as Sleafar identified first, as reflected in your edited question.

    0 讨论(0)
  • 2021-01-06 01:23

    The Instant type doesn't contain timezone information. You can define a timezone for the formatter like this:

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

    Edit:

    Actually there are reasons to have formatters without an assigned timezone, as well as date/time representing classes. Consider the following example:

    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 represents an actual point in time without referring to a specific location and therefore without a timezone. The exceptions (1) and (2) are raised because to represent the specific point in time the formatter needs a timezone to make the output readable for humans.
    • ZonedDateTime represents an actual point in time also assigned to a specific timezone. No problems at all to format them, but consider the last example. If you set a timezone in the formatter, you might get different results.
    • LocalDateTime doesn't represent an actual point in time. You can even assign a value which is invalid in some timezones, like when the clock is pushed forward 1 hour in case of daylight saving time. To get a real point in time you have to combine it with a timezone (like done in the example above). Exceptions (3) and (4) are raised, because the formatter wants to print a timezone value, which doesn't exist in this type.

    I can't tell why the designers opted to discover the described problems at runtime instead of compile time. Maybe it would make the class hierarchy too complicated.

    0 讨论(0)
  • 2021-01-06 01:34

    The conversion to Instant succeeds without problem. The problem is the formatter. Use ISO_INSTANT formatter instead of RFC_1123_DATE_TIME then you should go:

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

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

    If you really want to have RFC_1123 format, you have to declare a timezone.

    Either append it to the formatter :

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

    or convert the Instant to a ZonedDateTime:

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

    --> Mon, 20 Jul 2015 21:11:53 GMT

    0 讨论(0)
提交回复
热议问题