Last Friday I had a moment of panic. While investigating why different run-time libraries might interpret file timestamps differently, I noticed that even Windows doesn’t always agree with itself. When was dos4gw.exe
last modified, at 10:14 PM or 9:14 PM?
For some (but not all) files, the dir
command in cmd
shows timestamps that are off by an hour compared to timestamps shown by Explorer or PowerShell. How is this possible? And is either of those timestamps even correct?
A friend soon pointed me in the right direction: Daylight Saving Time, or DST.
Now it’s early March, and for files last written in recent months, the timestamps matched between cmd
and Explorer. For older files, they did not. The same pattern repeated for older files last written in previous years. Files written in winter had matching timestamps, files written in summer did not.
The effect is observable on Windows 10 and 11, as well as older versions going back to Windows 7. Windows Vista and previous releases do not exhibit this behavior—Explorer and cmd
show consistent (but wrong!) times.
Why oh Why?
Without reverse engineering cmd.exe
, I can only guess at the cause. It is highly likely that cmd
uses the FileTimeToLocalFileTime
API, for which Microsoft has a rather interesting Remarks section in their documentation:
To account for daylight saving time when converting a file time to a local time, use the following sequence of functions in place of using FileTimeToLocalFileTime:
- FileTimeToSystemTime
- SystemTimeToTzSpecificLocalTime
- SystemTimeToFileTime
In other words, FileTimeToLocalFileTime
is broken, and probably has been all along. As far as I can tell, FileTimeToLocalFileTime
determines the current offset from UTC, and applies it to all timestamp conversions. That is correct for timestamps taken when the UTC offset was the same as it is now, but incorrect for timestamps taken with a different UTC offset.
That is, when DST is not in use, FileTimeToLocalFileTime
incorrectly converts timestamps taken when DST was in use, and vice versa.
How Does It All Work?
The Win32 API presents file timestamps using the FILETIME
type. This time is based on UTC; in the NTFS file system, timestamps are stored in UTC, for other file systems (such as FAT and derivatives) the OS converts timestamps to UTC. Which opens a whole another can of worms, but that’s a separate discussion.
In any case, users are not interested in UTC. They care about their local time. Which means that for displaying timestamps, software has to convert timestamps to local time. And that’s exactly what FileTimeToLocalFileTime
does… only badly.
As Microsoft’s own documentation says, instead of FileTimeToLocalFileTime
, applications can use the sequence FileTimeToSystemTime
/ SystemTimeToTzSpecificLocalTime
/ SystemTimeToFileTime
. The SystemTimeToTzSpecificLocalTime
API correctly takes DST into account.
Applications can also take a different tack. FILETIME
timestamps in UTC can be fairly simply converted to POSIX style time_t
timestamps, or applications can use run-time library routines like stat()
that return timestamps in time_t
format. These timestamps can be processed with Standard C library functions such as localtime()
.
In either case, DST will be handled correctly (SystemTimeToTzSpecificLocalTime
and localtime()
both do the right thing)… and the local times will not always match what cmd
shows.
Conversion Pitfalls
Recording timestamps in UTC is the obvious correct design decision. The OS should be independent of the local time zone; for one thing, different users concurrently using the system might conceivably be using different time zones.
In addition, converting from UTC to local time is unambiguous, but conversion in the opposite direction is not. When switching from DST to standard time, the local time might switch from 2:00 AM DST to 1:00 AM standard time (the exact time varies by time zone!). Which means that on the day of the switchover, the local time hits 1:30 AM twice, and it is impossible to unambiguously convert such local time to UTC without knowing whether DST was in effect or not at the time. And that is information which is usually lost.
Similarly comparing timestamps must be done in UTC if the timestamps might have been taken in different time zones. Local times are impossible to work with in a global context, and should only be used for display purposes. But converting from UTC to local time is not entirely trivial.
Update: To explicitly answer the question posed at the beginning of this post: The 10:14 PM timestamp shown by Explorer is correct, and the 9:14 PM timestamp shown by cmd
is not.
Also worth noting is that the “Automatically adjust clock for daylight saving changes” or “Adjust for daylight saving time automatically” setting in Windows has an effect on the timestamps shown. That may seem surprising, but it’s completely logical. When converting UTC to local time, it does make a difference whether DST is in effect or not.
IIRC, msvcrt’s stat function also returns different result depending on whether DST is in effect or not – you can observe this in Windows version of GIMP, which will always do a full query of its plugins after DST switchover instead of relying on cache.
Hmm… it really shouldn’t, because stat() returns time_t which is UTC, and the timestamps in NTFS are also UTC based. Do you remember which runtime it was?
Unless of course the files were on a FAT related filesystem… in which case yes the timestamps would change.
“In any case, users are not interested in UTC.”
A few tens of millions of us are! *grin*
It’s UTC right now where I am, or as most people would call it, GMT. I’ve a PC dedicated to running a weather station and that stays in UTC all year round – weird things happen with observations when the clock automatically goes forward or back an hour.
Time stamps have always been a bit of fun, though, right back to the early days when there were many, many files around with dates just after midnight on the 1st Jan 1980… my first PC was an IBM PC XT, cast off from my dad’s work, and that didn’t have a battery to save the time. Typing in the date and time each time was a bit boring, and from the looks of it others felt the same, hence all those default dates!
It’s funny that modern Windows gets the dates and times confused when DST is in effect, depending on where you look… all these years and I hadn’t noticed it.
If you’re lucky enough that UTC happens to be your local time then yeah, it’s the time you’re interested in 🙂
I hate the 1980-01-01 timestamps, you know they have to be wrong because DOS didn’t even exist at that point. But clearly there was a significant class of users who did not bother entering the right date and time when booting their PC or PC/XT.
I can attest to the fact that the Windows timestamps problems are not very noticeable — usually for timestamps a few months (let alone a few years) in the past, it really does not matter if they’re off by an hour or not.
The problem is also much less noticeable when they’re consistently wrong. For example with makefiles, timestamp mismatches are definitely noticeable. But if the OS gets everything wrong the same way, it ends up being invisible.
It gets even more fun if you dig a bit! Not only were there plenty of files around with the old 01/01/80 date back in the day, but it seems Windows NT defaults to an even older date. One of the old disks I had contained pinball games from the old (self-booting) Pinball Construction Set. Nothing unusual there, but one of those disks had a file with no date at all.
What does Windows 11 make of it? Well…
K:\games\pinb>dir
Volume in drive K is OldStuff
Volume Serial Number is 100C-B783
Directory of K:\games\pinb
08/03/2025 16:48 .
08/03/2025 16:48 ..
27/03/1986 17:47 64,512 FREESTYL.COM
08/09/1986 01:48 64,512 MYSTERY.COM
21/01/1988 21:10 487 PINBALL.DOC
23/05/1986 11:26 64,512 RAIN.COM
01/01/1601 00:00 64,512 SCORPION.COM
28/02/1986 13:18 64,512 TWILZONE.COM
6 File(s) 323,047 bytes
2 Dir(s) 84,024,913,920 bytes free
I guess the “zero hour” as far as NT is concerned is the 1st Jan 1601, quite impressive!
With drifting RTCs, accelerated CPUs moving the clock faster, and cassette port access stopping the clock, a PC having file times within a few hours of the correct time would be doing very well. I know the phone company was willing to purchase the expensive clock keeping addons but then losing a few seconds a day on the computer’s clock would mean losing millions of dollars of call revenue.
It makes sense that DIR doesn’t adjust its conversion depending on date. A full scale DIR /s from root could take a long time which would be even longer if every file had its date compared to decide DST status.
> Do you remember which runtime it was?
GIMP 1.x and 2.x use msvcrt.dll (GIMP 3 RCs use the newer ucrt).
Re “1980-01-01” dates:
It would be great if IBM had thought of marking that date as “undefined”, or rather perhaps mark all of January 1980 as “undefined”.
General fun fact re DST: In Sweden the public transport agencies tend to use hour numbers that are greater than 23 for anything scheduled to run after midnight until a pause that almost always happens sometime during the night. Thus what is presented as 01:30 to the public is 25:30 in the internal documents.
Btw is it really always a good idea to show file times in your local time zone? And for that sake, is it always a good idea for time stamps for mails and whatnot? It seems like the best would be to present both at the same time, and not doing that could lead to various problems when communicating with people across time zones. I.E. someone who works at a fix set of hours and is instructed to do something right when they start working or just before they leave, and the time stamps might be misinterpreted as if they wasted an hour before/after doing their task.
You have an additional wrinkle with this time riddle. What is the SMB/CIFS protocol reporting as time stamps? Ultimately that is where the timestamp information comes from on network shares.
I just had to deal with this annoyance with Netatalk. Prior to AFP 3.0 and MacOS X, all AFP clients just used whatever timestamp the server reported with no correction. Starting with AFP 3.0, Apple fixed this to the proper UNIX way and all timestamps “over the wire” must be UTC requiring the client to shift them to local time and back.
Naturally, legacy clients get a UTC timestamp which is going to how many hours off from local time. The problem is writing files. The client assumes local time, but the server is expecting timestamps in UTC, so written files accumulate timestamp errors.
We won’t go into the hell that is maintaining accurate time stamps when copying files from a FAT32 drive to NTFS………
The DOS 0.90 disk had files with no date stamp at all. It’s the only disk I’ve seen like this. Later DOS releases had everything fixed to the release date.
Yes. An “empty” timestamp (all zeros) is not shown by the DOS DIR command.
I know that maintaining timestamps in directory entries was one of IBM’s requirements and it was not present in the original 86-DOS (which at first used 16-byte directory entries, not 32-byte).
Also, even PC DOS 1.0 only recorded the date, not time. PC DOS 1.1 started recording the time as well. Hence old 86-DOS and PC DOS images all have zero time stamps even when the dates are sensible.
I have intentionally ignored network file systems. It all depends on the network protocol and the client/server software. Windows itself does not really care, it’s the network client’s business to present and record UTC-based timestamps.
FAT-based file systems are indeed a special kind of hell. The OS just makes a guess what the timestamps really mean. Sometimes it’s right, sometimes it’s not.
Jeff Parson from PCJS wrote about his problems with time: https://www.pcjs.org/blog/2017/12/23/
My country stopped using daylight savings a year or two ago. Of course, the old operating systems don’t have this change. I said no problem simply put Central Standard Time without daylight saving, but for example old versions of Android don’t have this option, they only have an option for “country”.
It’s fun when you have 2 operating systems dual booting in a PC. In my case Windows and Linux, 2 changes of time every time you boot the operating systems after the daylight time was active or inactive. And almost every time have to change the time manually.
Also UNIX traditionally have the RTC at UTC, Windows NT (I don’t remember what is the default), but you can change it in the registry if is UTC or Local Time, and Windows 9x, DOS is Local Time. More fun times dual booting…
In the 90’s at a company that I worked, they bought some Acer PC’s with Windows 9x because their were very cheap. Their RTC’s were horribly inaccurate, something like 3 or 5 minutes difference with actual time after an hour and this caused problems with the network (I think NFS), so we have to program ntpdate every 30 minutes or every hour to correct the RTC.
date/time is a mess, sometimes even in the “real world”.
It could also be that cmd ends up using the old DST start/end dates. When Vista and older were released, DST started on the first Sunday in April. Starting in 2007, a couple of months after Vista, DST started going into effect on the second Sunday in March.
Does the hour offset continue to exist if you change the system date to April 7 or later?