pythonntfs

What is the binary format of NTFS timestamp?


I am trying to learn the raw binary format of every type of NTFS record and I am making great progress. Related question

I have found Active Disk Editor and it tells me all about the offsets and field names and such for NTFS Master File Table File Records, and there is one thing I don't understand.

In attribute 0x10 $STANDARD_INFORMATION how are the timestamps encoded?

Like, this 8 byte sequence: b'\xb0\x37\x86\x69\x36\x1e\xd7\x01', why does it represent 2021-03-21 09:41?

How is it encoded?

I know most numbers in NTFS records are little endian. However, trying to convert it directly to integer will of course yield a very high number, with big endian byte order the number is even higher:

In [133]: int.from_bytes(b'\xb0\x37\x86\x69\x36\x1e\xd7\x01', 'little')
Out[133]: 132607933078190000

In [134]: int.from_bytes(b'\xb0\x37\x86\x69\x36\x1e\xd7\x01', 'big')
Out[134]: 12697765460832081665

Trying to use these numbers as datetime.fromtimestamp arguments will raise OSError:

In [135]: from datetime import datetime

In [136]: datetime.fromtimestamp(132607933078190000)
---------------------------------------------------------------------------
OSError                                   Traceback (most recent call last)
Cell In[136], line 1
----> 1 datetime.fromtimestamp(132607933078190000)

OSError: [Errno 22] Invalid argument

Using the first 10 digits will give a date that is too early:

In [137]: datetime.fromtimestamp(int('132607933078190000'[:11]))
Out[137]: datetime.datetime(2390, 3, 21, 17, 41, 47)

In [138]: datetime.fromtimestamp(int('12697765460832081665'[:11]))
Out[138]: datetime.datetime(2372, 5, 18, 5, 4, 20)

In [139]: datetime.fromtimestamp(int('12697765460832081665'[:10]))
Out[139]: datetime.datetime(2010, 3, 28, 19, 42, 26)

In [140]: datetime.fromtimestamp(int('132607933078190000'[:10]))
Out[140]: datetime.datetime(2012, 1, 9, 11, 22, 10)

So how is this timestamp encoded?


Edit

This is not a duplicate as the suggested duplicate question doesn't mention converting the 8-byte little endian sequence to integer and none of the answers included this conversion.


Solution

  • There's a comment to the question that gives the source.

    Here's the Python code to do the conversion:

    ns100 = int.from_bytes(b'\xb0\x37\x86\x69\x36\x1e\xd7\x01', 'little')
    timestamp = datetime.datetime(1601, 1, 1) + datetime.timedelta(microseconds=ns100 // 10)