2

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

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

FILETIME 结构是一个 64 位的值,表示自 1601 年 1 月 1 日(协调世界时 (UTC))以来经过的 100 纳秒间隔的数量。typedef struct _FILETIME { DWORD dwLowDateTime; DWORD dwHighDateTime; 文件时间,*PFILETIME,*LPFILETIME;dwLowDateTime:一个 32 位无符号整数,包含文件时间的低位。dwHighDateTime:一个 32 位无符号整数,包含文件时间的高位。

例如,这里是长130280867040000000

所以计算的高低

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

这么高=30333378 和低=552794112

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

4

2 回答 2

2

啊,当我像这样将字节分成两半时,我在叫错树。

基本上它只是说单位是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)
于 2019-12-11T17:50:43.000 回答
1

要以 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 整数都是无符号的。Javalong已签名。所以在 30828 年的某个时候,我们将开始得到非常错误的结果。以防万一我们应该在long值为负数时抛出异常。

于 2019-12-12T03:39:48.577 回答