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

时间:2019-12-11 17:37:53

标签: java c# time datetime-conversion java.time.instant

在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日以来已经过了100纳秒的间隔,   协调世界时(UTC)。 typedef struct _FILETIME {DWORD   dwLowDateTime; DWORD dwHighDateTime; } FILETIME,   * PFILETIME,   * LPFILETIME; dwLowDateTime:32位无符号整数,包含文件时间的低位。 dwHighDateTime:32位无符号   包含文件时间高阶位的整数。

例如,这里是长130280867040000000

所以高点和低点用

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

如此高= 30333378 和低= 552794112

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

2 个答案:

答案 0 :(得分:1)

当我像这样将字节分成两半时,我正在吠叫错误的树。

基本上是说单位是100ns。

纪元也有不同的基准时间。因此,您还必须添加偏移量。

就是这样:

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