In the Microsoft Spec, DATETIME
is represented as 2 32-bit integers: low
and high
Reference: https://docs.microsoft.com/en-us/open
Ah I was barking up the wrong tree when I split the bytes in half like that.
Basically it's just saying that the units are in 100ns.
And the Epoch has a different base time too. So you have to add the offset as well.
So it is:
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)
For converting with 1 second precision your own answer is just fine. In case you also need to convert the fraction of second, here’s one way to do that.
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);
Output is:
2013-11-05T00:58:24Z
Let’s try to put 1 more tick on your oroginal value; it should add 100 nanoseconds.
long fullval = 130_280_867_040_000_001L;
2013-11-05T00:58:24.000000100Z
So so it does.
Caveat for very far future dates: According to your quote the Microsoft integers are both unsigned. A Java long
is signed. So some time in year 30828 we will start getting results that are very wrong. Just in case we ought to throw an exception if the long
value is negative.