Modify file create / access / write timestamp with python under windows
Solution 1
There are two places where you might want to correct for winter/summer difference of one hour. In both cases, we make use of the tm_isdst
field, which time.localtime
conveniently calculates to tell us whether Daylight Savings Time (DST) was in effect for a particular timestamp.
Input Correction
If you are setting a winter timestamp during summer, or vice versa, it will become off by an hour when its matching season comes around unless you compensate before calling SetFileTime
:
now = time.localtime()
createTime = Time(time.mktime(cTime_t) + 3600 * (now.tm_isdst - cTime_t.tm_isdst))
accessTime = Time(time.mktime(aTime_t) + 3600 * (now.tm_isdst - aTime_t.tm_isdst))
modifyTime = Time(time.mktime(mTime_t) + 3600 * (now.tm_isdst - mTime_t.tm_isdst))
SetFileTime(fh, createTime, accessTime, modifyTime)
Output Correction
To make Python reports match Windows Explorer, we apply the correction before calling strftime
:
# check if all was ok
now = time.localtime()
ctime = os.path.getctime(fName)
mtime = os.path.getmtime(fName)
atime = os.path.getatime(fName)
ctime += 3600 * (now.tm_isdst - time.localtime(ctime).tm_isdst)
mtime += 3600 * (now.tm_isdst - time.localtime(mtime).tm_isdst)
atime += 3600 * (now.tm_isdst - time.localtime(atime).tm_isdst)
ctime = time.strftime(format,time.localtime(ctime))
mtime = time.strftime(format,time.localtime(mtime))
atime = time.strftime(format,time.localtime(atime))
Both Corrections
Beware, if you apply both, your Python output will again seem to mismatch your input. This may be desirable (see below), but if it bothers you:
- Choose only Input Correction if you prefer timestamps that look right at their native time of year.
- Choose only Output Correction if you're used to seeing them jump an hour twice a year as DST takes effect and then goes away.
Why is DST so inconsistent?
Python and Windows have chosen different methods to convert timestamps between UTC and the local time zone:
Python uses the DST code that was in effect at the timestamp. This way, the time stamp has a consistent representation year-round.
Windows uses the DST code in effect right now. This way, all time stamps shown have the same implicit code.
This is evident if you use '%Z' to include the time zone in the converted string (PST vs. PDT, for example) but since most apps (including Windows Explorer) do not, an apparent one-hour inconsistency can manifest.
Example
When printed with explicit time codes, it becomes clear that the stamps in each column really do all represent the same instant in time:
File #1 (January) File #2 (June)
2000-01-30 20:00:00 UTC 2000-06-22 20:00:00 UTC
observed in January in California:
2000-01-30 12:00:00 PST 2000-06-30 13:00:00 PDT [Python]
2000-01-30 12:00:00 PST 2000-06-30 12:00:00 PST [Windows]
observed in June in California:
2000-01-30 12:00:00 PST 2000-06-30 13:00:00 PDT [Python]
2000-01-30 13:00:00 PDT 2000-06-30 13:00:00 PDT [Windows]
observed in June in New York:
2000-01-30 15:00:00 EST 2000-06-30 16:00:00 EDT [Python]
2000-01-30 16:00:00 EDT 2000-06-30 16:00:00 EDT [Windows]
It would be nice if we could ask strftime to honor the tm_isdst field, to match Windows Explorer and most other apps that display file timestamps, but at least there's a simple workaround to do the calculation ourselves.
def adjustForDST (seconds):
now = time.localtime()
correction = 60*60 * (now.tm_isdst - time.localtime(seconds).tm_isdst)
return seconds + correction
time.strftime(format, time.localtime(adjustforDST(mtime)))
Sources:
http://bytes.com/topic/python/answers/655606-python-2-5-1-broken-os-stat-module http://search.cpan.org/~shay/Win32-UTCFileTime-1.58/lib/Win32/UTCFileTime.pm
If the cpan link breaks again with a new revision, find it this way:
https://www.google.com/search?q=UTCFileTime.pm
Solution 2
Using os.utime
, you can change the atime, mtime (no ctime).
>>> import time
>>> import os
>>> t = time.mktime(time.strptime('16.01.2014 00:00:00', '%d.%m.%Y %H:%M:%S'))
>>> t
1389798000.0
>>> os.utime('..\path\to\file', (t,t)) # <---
>>> os.path.getmtime('..\path\to\file')
1389798000.0
Related videos on Youtube
Michael Hecht
Updated on October 28, 2022Comments
-
Michael Hecht over 1 year
I tried to find an easy way to modifiy a file timestamp under windows using python, but there was not much clear information on the web. After searching a while I got a solution. To shorten the search for others, the code follows here.
It might be done easier and more beautiful, but it works. The only thing I didn't solve is the summer time - winter time issue, i.e. if a time in summer is given, the result differs by one hour. Maybe someone can add a correction?
from win32file import CreateFile, SetFileTime, GetFileTime, CloseHandle from win32file import GENERIC_READ, GENERIC_WRITE, OPEN_EXISTING from pywintypes import Time import time import sys import os if len(sys.argv)<5: pfile = os.path.basename(sys.argv[0]) print "USAGE:\n\t%s <createTime> <modifyTime> <accessTime> <FileName>\n" % pfile print "EXAMPLE:" print '%s "01.01.2000 00:00:00" "01.01.2000 00:00:00" "01.01.2000 00:00:00" file' % (pfile) sys.exit() # get arguments cTime = sys.argv[1] # create mTime = sys.argv[2] # modify aTime = sys.argv[3] # access fName = sys.argv[4] # specify time format format = "%d.%m.%Y %H:%M:%S" offset = 0 # in seconds # create struct_time object cTime_t = time.localtime(time.mktime(time.strptime(cTime,format))+offset) mTime_t = time.localtime(time.mktime(time.strptime(mTime,format))+offset) aTime_t = time.localtime(time.mktime(time.strptime(aTime,format))+offset) # visually check if conversion was ok print print "FileName: %s" % fName print "Create : %s --> %s OK" % (cTime,time.strftime(format,cTime_t)) print "Modify : %s --> %s OK" % (mTime,time.strftime(format,mTime_t)) print "Access : %s --> %s OK" % (aTime,time.strftime(format,aTime_t)) print # change timestamp of file fh = CreateFile(fName, GENERIC_READ | GENERIC_WRITE, 0, None, OPEN_EXISTING, 0, 0) createTime, accessTime, modifyTime = GetFileTime(fh) print "Change Create from",createTime,"to %s" % (time.strftime(format,cTime_t)) print "Change Modify from",modifyTime,"to %s" % (time.strftime(format,mTime_t)) print "Change Access from",accessTime,"to %s" % (time.strftime(format,aTime_t)) print createTime = Time(time.mktime(cTime_t)) accessTime = Time(time.mktime(aTime_t)) modifyTime = Time(time.mktime(mTime_t)) SetFileTime(fh, createTime, accessTime, modifyTime) CloseHandle(fh) # check if all was ok ctime = time.strftime(format,time.localtime(os.path.getctime(fName))) mtime = time.strftime(format,time.localtime(os.path.getmtime(fName))) atime = time.strftime(format,time.localtime(os.path.getatime(fName))) print "CHECK MODIFICATION:" print "FileName: %s" % fName print "Create : %s" % (ctime) print "Modify : %s" % (mtime) print "Access : %s" % (atime)
-
Michael Hecht over 10 yearsWell, yes, there is an easy way to change the atime and mtime but NOT ctime. That's why I took the hard way :)
-
Pat over 9 yearsI wanted to use a datetime to set the mtime, so I had to do: t = time.mktime(d.timetuple())
-
falsetru over 9 years@Pat, If you use Python 3.3+, you can use [
datetime.datetime.timestamp
]( docs.python.org/3/library/…):t = d.timestamp()
-
Pat over 9 yearsThanks! I am on 2.7 in this project, but it's good to know the more modern way.
-
jfs over 9 yearsthere are no DST transitions if you express your time using timestamps such POSIX timestamp (what Python expects), FILETIME (Windows, you can easily convert one into another -- note: no DST adjustments). If function requires local time as an input; it is broken by design if you need to interpret it in some way i.e., it is ok to display local time but you should not try to do even simple arithmetics with it.