Delphi uses the same FileTimeToDosDateTime in FileAge().
Only in the deprecated version of FileAge(). It was replaced over a decade ago with a newer overloaded version that outputs a full TDateTime without truncating off the milliseconds.
Argh, You are correct. The FileAge(Filename) with one parameter is deprecated. FileAge(FileName, DateTime): Boolean is the new one. And that returns the correct milliseconds in Delphi. But in FPC that overloaded version uses the FileTimeToDateTime internally again, which strips the milliseconds. Delphi uses TrySystemTimeToDateTime() to convert the FileTime to DateTime (which does support milliseconds).
That would be easily fixed in FPC to use SystemTimeToDateTime() too but the next problem is that FPC uses the old FindFirst() to get the time information (which isn't accurate to the millisecond).
And to top it off.... internally that same FindFirst in FPC uses the the more accurate FindFirstFileW it also uses in the FileAge(Filename) but it converts the ftLastWriteTime back to WinToDosTime() for the time in the SearchRec.
Yeah... this is really a mess

So Delphi:
FileAge(Filename) -> uses GetFileAttributesEx() to get ftLastWriteTime but after that FileTimeToDosDateTime() which cuts ms
FileAge(Filename, TDateTime) -> uses GetFileAttributesEx() to get ftLastWriteTime which is converted with TrySystemTimeToDateTime() which does support ms
And FPC:
FileAge(Filename) -> uses FindFirstFileW() to get ftLastWriteTime but uses WinToDosTime() which cuts milliseconds (no problem, compatibility)
FileAge(Filename, TDateTime) -> uses FindFirst -> which uses FindFirstFileW() to get ftLastWriteTime but ms is cut in FindFirst by WinToDosTime() (incompatible)
(note ftLastWriteTime supports milliseconds)
So in FPC the FileAge(Filename, TDateTime) should be
FileAge(Filename, TDateTime) -> uses FindFirstFileW() to get ftLastWriteTime which is converted with SystemTimeToDateTime() which does support ms
(so with FindFirstFileW() and not via FindFirst() which cuts the ms)