From APFS documentation it is revealed that the new timestamp has a nano second resolution. From my data I can see several timestamps in what appears to be the root directory for a test APFS volume I created. Armed with this information, it was pretty easy to guess the epoch - it is the Unix epoch.
If you need to read this timestamp in python (and convert to python datetime), the following function will do this:
import datetime
def ConvertApfsTime(ts):
try:
return datetime.datetime(1970,1,1) + datetime.timedelta(microseconds=ts / 1000. )
except:
pass
return None
Update: As noted by Joachim, the timestamp is an int64, and has been corrected in the above code.
ApfsTimeStamp = number of nano-seconds since 1-1-1970
If you like to use the 010 editor for analysis, put the following code in your Inspector.bt or InspectorDates.bt file:
//----------------------------------------------------------------
// ApfsTime
// 64-bit integer, number of nanoseconds since 01/01/1970 00:00:00
typedef int64 ApfsTime <read=ApfsTimeRead, write=ApfsTimeWrite>;
FSeek( pos ); ApfsTime _aft <name="ApfsTimes">;
string ApfsTimeRead( ApfsTime t )
{
// Convert to FILETIME
return FileTimeToString( t/100L + 116444736000000000L );
}
int ApfsTimeWrite( ApfsTime &t, string value )
{
// Convert from FILETIME
FILETIME ft;
int result = StringToFileTime( value, ft );
t = (((int64)ft - 116444736000000000L)*100L);
return result;
}
import datetime
def ConvertApfsTime(ts):
try:
return datetime.datetime(1970,1,1) + datetime.timedelta(microseconds=ts / 1000. )
except:
pass
return None
Update: As noted by Joachim, the timestamp is an int64, and has been corrected in the above code.
To me it looks more likely the the timestamp is a signed value.
ReplyDelete```
touch -t 194001010000 /Volumes/SingleVolume/myfile.txt
-rw-r--r-- 1 user staff 0 Jan 1 1940 myfile.tzt
```
```
printf "0x%x\n" $(( `date -u -d"1940-01-01 00:00:00" +"%s"` * 1000000000 ))
0xf2dc649c1c6e0000
```
```
00000000: 02 00 00 00 00 00 00 00 14 00 00 00 00 00 00 00 ........ ........
00000010: 3a c7 32 1b a1 90 54 15 00 60 b5 eb 55 61 dc f2 :.2...T. .`..Ua..
00000020: 01 68 33 1b a1 90 54 15 00 60 b5 eb 55 61 dc f2 .h3...T. .`..Ua..
00000030: 00 80 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ........ ........
00000040: 01 00 00 00 00 00 00 00 63 00 00 00 63 00 00 00 ........ c...c...
00000050: a4 81 00 00 00 00 00 00 00 00 00 00 01 00 10 00 ........ ........
00000060: 04 02 0b 00 6d 79 66 69 6c 65 2e 74 78 74 00 00 ....myfi le.txt..
00000070: 00 00 00 00 ....
```
`00 60 b5 eb 55 61 dc f2` matches the calculated value 0xf2dc649c1c6e0000
You are correct Joachim. This should be int64, not uint64. Thanks for catching that bug (untested use case). I will change all my APFS library code to reflect this.
ReplyDeleteThx, for the reader, I've seen this error in several publications about APFS by now.
ReplyDelete