Archives
- October 2025
- September 2025
- August 2025
- July 2025
- June 2025
- May 2025
- April 2025
- March 2025
- February 2025
- January 2025
- December 2024
- November 2024
- October 2024
- September 2024
- August 2024
- July 2024
- June 2024
- May 2024
- April 2024
- March 2024
- February 2024
- January 2024
- October 2023
- September 2023
- August 2023
- July 2023
- June 2023
- May 2023
- April 2023
- March 2023
- January 2023
- December 2022
- November 2022
- October 2022
- September 2022
- July 2022
- June 2022
- May 2022
- April 2022
- March 2022
- February 2022
- January 2022
- December 2021
- November 2021
- October 2021
- September 2021
- August 2021
- July 2021
- June 2021
- May 2021
- April 2021
- March 2021
- February 2021
- January 2021
- December 2020
- November 2020
- October 2020
- September 2020
- August 2020
- July 2020
- June 2020
- May 2020
- April 2020
- March 2020
- February 2020
- January 2020
- December 2019
- November 2019
- October 2019
- September 2019
- August 2019
- July 2019
- June 2019
- May 2019
- April 2019
- March 2019
- February 2019
- January 2019
- December 2018
- November 2018
- October 2018
- August 2018
- July 2018
- June 2018
- May 2018
- April 2018
- March 2018
- February 2018
- January 2018
- December 2017
- November 2017
- October 2017
- August 2017
- July 2017
- June 2017
- May 2017
- April 2017
- March 2017
- February 2017
- January 2017
- December 2016
- November 2016
- October 2016
- September 2016
- August 2016
- July 2016
- June 2016
- May 2016
- April 2016
- March 2016
- February 2016
- January 2016
- December 2015
- November 2015
- October 2015
- September 2015
- August 2015
- July 2015
- June 2015
- May 2015
- April 2015
- March 2015
- February 2015
- January 2015
- December 2014
- November 2014
- October 2014
- September 2014
- August 2014
- July 2014
- June 2014
- May 2014
- April 2014
- March 2014
- February 2014
- January 2014
- December 2013
- November 2013
- October 2013
- September 2013
- August 2013
- July 2013
- June 2013
- May 2013
- April 2013
- March 2013
- February 2013
- January 2013
- December 2012
- November 2012
- October 2012
- September 2012
- August 2012
- July 2012
- June 2012
- May 2012
- April 2012
- March 2012
- February 2012
- January 2012
- December 2011
- November 2011
- October 2011
- September 2011
- August 2011
- July 2011
- June 2011
- May 2011
- April 2011
- March 2011
- January 2011
- November 2010
- October 2010
- August 2010
- July 2010
Time Trouble
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.
20 Responses to Time Trouble
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?
>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.
It is not so simple. Timestamp is always the same in UTC but reflection to current time location can be different. And the right answer to question “what was the local time when this UTC time?” needs the HISTORY of TZ offsets & DST rules (yes, they CAN change) for this location.
And the good question is “does MS account such changes at all and for how long time distances into the past” π
I use a file synchronization tool to synchronize media files between my Windows laptop, a Samba share on a Linux box, and a couple of ExFAT formatted external drives, which uses the file modification time to determine files need updating. The tool has an option to tell it to ignore any time differences of precisely an hour to get around various other DST related problems, and other offsets can also be added, if needed.
Including time zone changes in the past could lead to international incidents as some nations have announced new time zones as part of an effort to be distinct from another. Change to use the previous time zone and that would be denying existence of the country. It would also take a lot of memory to store a complete table going back 50 years and a lot of time comparing every date and time to that table when listing a large directory.
The current ls.c file is larger than the complete source code for early versions of DOS. Trying to handle all those unusual cases does add up.
> And the right answer to question "what was the local time when this UTC time?" needs the HISTORY of TZ offsets & DST rules (yes, they CAN change) for this location.
And the good question is "does MS account such changes at all and for how long time distances into the past"
Can’t say about MS and Windows, but modern *nixes typically(*) use current tzdata (zoneinfo db) and don’t keep history. Therefore all possible operations, like ftime comparisons, updating ftime, are done in UTC. There is easy way to override tz for process:
“TZ=UTC date” or even “TZ=/tmp/old_Havana_tz date”.
> The current ls.c file is larger than the complete source code for early versions of DOS. Trying to handle all those unusual cases does add up.
The ls source is big, but that’s because there are many options, colorization, formatting, unicode handling, recursive tree walking, etc. The time conversion encapsulated in localtime(3).
(*) The old HP-UX used proprietary zoneinfo db and kept the history of tz changes.
Most modern operation systems use database from IANA ( see https://www.iana.org/time-zones ) β but that switch only happened after some astrology company tried to shut down the whole thing that’s used by billions of people but was maintained by a couple of volunteers in their spare time ( see https://lwn.net/Articles/461955/ ).
Raymond Chen previously covered the topic, too: https://devblogs.microsoft.com/oldnewthing/20130308-00/?p=5023
This site uses Akismet to reduce spam. Learn how your comment data is processed.