Modify file create / access / write timestamp with python under windows

14,796

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
Share:
14,796

Related videos on Youtube

Michael Hecht
Author by

Michael Hecht

Updated on October 28, 2022

Comments

  • Michael Hecht
    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
    Michael Hecht over 10 years
    Well, yes, there is an easy way to change the atime and mtime but NOT ctime. That's why I took the hard way :)
  • Pat
    Pat over 9 years
    I wanted to use a datetime to set the mtime, so I had to do: t = time.mktime(d.timetuple())
  • falsetru
    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
    Pat over 9 years
    Thanks! I am on 2.7 in this project, but it's good to know the more modern way.
  • jfs
    jfs over 9 years
    there 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.