java.time.DateTimeFormatter:需要始终呈现毫秒的ISO_INSTANT

Flo*_*ent 15 java datetime-format java-8

我正在尝试将日期时间管理的各种代码混合清理到只有Java 8 java.time命名空间.现在我有一个小问题,默认DateTimeFormatterInstant.该DateTimeFormatter.ISO_INSTANT格式只能说明毫秒时,他们不等于零.

时代被渲染为1970-01-01T00:00:00Z而不是1970-01-01T00:00:00.000Z.

我做了一个单元测试来解释这个问题以及我们需要如何将最终日期相互比较.

@Test
public void java8Date() {
    DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT;
    String epoch, almostEpoch, afterEpoch;

    { // before epoch
        java.time.Instant instant = java.time.Instant.ofEpochMilli(-1);
        almostEpoch = formatter.format(instant);
        assertEquals("1969-12-31T23:59:59.999Z", almostEpoch );
    }

    { // epoch
        java.time.Instant instant = java.time.Instant.ofEpochMilli(0);
        epoch = formatter.format(instant);
        // This fails, I get 1970-01-01T00:00:00Z instead
        assertEquals("1970-01-01T00:00:00.000Z", epoch );
    }

    { // after epoch
        java.time.Instant instant = java.time.Instant.ofEpochMilli(1);
        afterEpoch = formatter.format(instant);
        assertEquals("1970-01-01T00:00:00.001Z", afterEpoch );
    }

    // The end game is to make sure this rule is respected (this is how we order things in dynamo):
    assertTrue(epoch.compareTo(almostEpoch) > 0);
    assertTrue(afterEpoch.compareTo(epoch) > 0); // <-- This assert would also fail if the second assert fails

    { // to confirm we're not showing nanos
        assertEquals("1970-01-01T00:00:00.000Z", formatter.format(Instant.EPOCH.plusNanos(1)));
        assertEquals("1970-01-01T00:00:00.001Z", formatter.format(Instant.EPOCH.plusNanos(1000000)));
    }
}
Run Code Online (Sandbox Code Playgroud)

Flo*_*ent 13

好的,我查看了源代码,它非常简单:

DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendInstant(3).toFormatter();
Run Code Online (Sandbox Code Playgroud)

我希望它适用于所有场景,它可以帮助其他人.不要犹豫,添加更好/更清洁的答案.

只是为了解释它的来源,在JDK的代码中,

ISO_INSTANT 定义如下:

public static final DateTimeFormatter ISO_INSTANT;
static {
    ISO_INSTANT = new DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .appendInstant()
            .toFormatter(ResolverStyle.STRICT, null);
}
Run Code Online (Sandbox Code Playgroud)

DateTimeFormatterBuilder::appendInstant声明为:

public DateTimeFormatterBuilder appendInstant() {
    appendInternal(new InstantPrinterParser(-2));
    return this;
}
Run Code Online (Sandbox Code Playgroud)

构造函数InstantPrinterParser签名是:

InstantPrinterParser(int fractionalDigits)
Run Code Online (Sandbox Code Playgroud)


Bas*_*que 5

由弗洛朗接受的答案是正确的,好的。

我只想补充一些说明。

提到的格式化程序DateTimeFormatter.ISO_INSTANT仅适用于Instant该类。其他类,例如OffsetDateTimeZonedDateTime可能默认使用其他格式化程序。

java.time 类提供高达纳秒的分辨率,比毫秒更精细的粒度。这意味着小数部分最多有 9 位数字,而不仅仅是 3 位数字。

的行为DateTimeFormatter.ISO_INSTANT因小数部分的位数而异。正如文档所说(强调我的):

格式化时,总是输出分秒。纳秒根据需要输出零、三、六或九位数字

因此,根据Instant对象中包含的数据值,您可能会看到以下任何输出:

2011-12-03T10:15:30Z

2011-12-03T10:15:30.100Z

2011-12-03T10:15:30.120Z

2011-12-03T10:15:30.123Z

2011-12-03T10:15:30.123400Z

2011-12-03T10:15:30.123456Z

2011-12-03T10:15:30.123456780Z

2011-12-03T10:15:30.123456789Z

Instant班,就是要java.time的基本构建块。经常将其用于数据传递、数据存储和数据交换。在生成数据的字符串表示以呈现给用户时,请使用OffsetDateTimeZonedDateTime