您如何在 Java 8 Instant 中表示 MS-DTYP `DATETIME`?

How do you represent MS-DTYP `DATETIME` in Java 8 Instant?

在 Microsoft 规范中,DATETIME 表示为 2 个 32 位整数:lowhigh

参考:https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/cca27429-5689-4a16-b2b4-9325d93e4ba2

The FILETIME structure is a 64-bit value that represents the number of 100-nanosecond intervals that have elapsed since January 1, 1601, Coordinated Universal Time (UTC). typedef struct _FILETIME { DWORD dwLowDateTime; DWORD dwHighDateTime; } FILETIME, *PFILETIME, *LPFILETIME; dwLowDateTime: A 32-bit unsigned integer that contains the low-order bits of the file time. dwHighDateTime: A 32-bit unsigned integer that contains the high-order bits of the file time.

例如这里是长130280867040000000

因此计算出的最高价和最低价是

int high = (int)(fullval >> 32);
int low = (int)fullval;

这么高=30333378 低 = 552794112

如何将这些计算为 Java 8 Instant?

啊,当我像那样将字节分成两半时,我找错了树。

基本上就是说单位是100ns。

而且 Epoch 也有不同的基准时间。所以你还必须添加偏移量。

原来是:

    private static final long DATETIME_EPOCH_DIFF_1601;
    static {
        LocalDateTime time32Epoch1601 = LocalDateTime.of(1601, Month.JANUARY, 1, 0, 0);
        Instant instant = time32Epoch1601.atZone(ZoneOffset.UTC).toInstant();
        DATETIME_EPOCH_DIFF_1601 = (instant.toEpochMilli() - Instant.EPOCH.toEpochMilli()) / 1000;
    }
    Instant answer = Instant.ofEpochSecond(fullval / 10000000 + DATETIME_EPOCH_DIFF_1601)

要以 1 秒的精度转换,您自己的答案就可以了。如果您还需要转换秒的小数部分,这里有一种方法可以做到这一点。

    Instant msFiletimeEpoch = Instant.parse("1601-01-01T00:00:00Z");
    // a tick is 100 nanoseconds
    int nanosPerTick = 100;
    long ticksPerSecond = TimeUnit.SECONDS.toNanos(1) / nanosPerTick;

    long fullval = 130_280_867_040_000_000L;

    long seconds = fullval / ticksPerSecond;
    long nanos = fullval % ticksPerSecond * nanosPerTick;

    Instant answer = msFiletimeEpoch.plusSeconds(seconds).plusNanos(nanos);

    System.out.println(answer);

输出为:

2013-11-05T00:58:24Z

让我们尝试在您的原始值上再打 1 个刻度;它应该增加 100 纳秒。

    long fullval = 130_280_867_040_000_001L;

2013-11-05T00:58:24.000000100Z

原来如此。

注意很远的未来日期:根据你的引述,Microsoft 整数都是无符号的。 A Java long 被签名。所以在 30828 年的某个时候,我们将开始得到非常错误的结果。以防万一我们应该在 long 值为负数时抛出异常。