How do I change the file creation date of a Windows file?

40,192

Solution 1

Yak shaving for the win.

import pywintypes, win32file, win32con
def changeFileCreationTime(fname, newtime):
    wintime = pywintypes.Time(newtime)
    winfile = win32file.CreateFile(
        fname, win32con.GENERIC_WRITE,
        win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE | win32con.FILE_SHARE_DELETE,
        None, win32con.OPEN_EXISTING,
        win32con.FILE_ATTRIBUTE_NORMAL, None)

    win32file.SetFileTime(winfile, wintime, None, None)

    winfile.close()

Solution 2

I did not want to bring the whole pywin32 / win32file library solely to set the creation time of a file, so I made the win32-setctime package which does just that.

pip install win32-setctime

And then use it like that:

from win32_setctime import setctime

setctime("my_file.txt", 1561675987.509)

Basically, the function can be reduced to just a few lines without needing any dependency other that the built-in ctypes Python library:

from ctypes import windll, wintypes, byref

# Arbitrary example of a file and a date
filepath = "my_file.txt"
epoch = 1561675987.509

# Convert Unix timestamp to Windows FileTime using some magic numbers
# See documentation: https://support.microsoft.com/en-us/help/167296
timestamp = int((epoch * 10000000) + 116444736000000000)
ctime = wintypes.FILETIME(timestamp & 0xFFFFFFFF, timestamp >> 32)

# Call Win32 API to modify the file creation date
handle = windll.kernel32.CreateFileW(filepath, 256, 0, None, 3, 128, None)
windll.kernel32.SetFileTime(handle, byref(ctime), None, None)
windll.kernel32.CloseHandle(handle)

For advanced management (like error handling), see the source code of win32_setctime.py.

Solution 3

install pywin32 extension first https://sourceforge.net/projects/pywin32/files/pywin32/Build%20221/

import win32file
import pywintypes

# main logic function
def changeFileCreateTime(path, ctime):
    # path: your file path
    # ctime: Unix timestamp

    # open file and get the handle of file
    # API: http://timgolden.me.uk/pywin32-docs/win32file__CreateFile_meth.html
    handle = win32file.CreateFile(
        path,                          # file path
        win32file.GENERIC_WRITE,       # must opened with GENERIC_WRITE access
        0,
        None,
        win32file.OPEN_EXISTING,
        0,
        0
    )

    # create a PyTime object
    # API: http://timgolden.me.uk/pywin32-docs/pywintypes__Time_meth.html
    PyTime = pywintypes.Time(ctime)

    # reset the create time of file
    # API: http://timgolden.me.uk/pywin32-docs/win32file__SetFileTime_meth.html
    win32file.SetFileTime(
        handle,
        PyTime
    )

# example
changeFileCreateTime('C:/Users/percy/Desktop/1.txt',1234567789)

Solution 4

import os
os.utime(path, (accessed_time, modified_time))

http://docs.python.org/library/os.html

At least it changes the modification time, without using win32 module.

Solution 5

Here's a more robust version of the accepted answer. It also has the opposing getter function. This addresses created, modified, and accessed datetimes. It handles having the datetimes parameters provided as either datetime.datetime objects, or as "seconds since the epoch" (what the getter returns). Further, it adjusts for Day Light Saving time, which the accepted answer does not. Without that, your times will not be set correctly when you set a winter or summer time during the opposing phase of your actual system time.

The major weakness of this answer is that it is for Windows only (which answers the question posed). In the future, I'll try to post a cross platform solution.

def isWindows() :
  import platform
  return platform.system() == 'Windows' 

def getFileDateTimes( filePath ):        
    return ( os.path.getctime( filePath ), 
             os.path.getmtime( filePath ), 
             os.path.getatime( filePath ) )

def setFileDateTimes( filePath, datetimes ):
    try :
        import datetime
        import time 
        if isWindows() :
            import win32file, win32con
            ctime = datetimes[0]
            mtime = datetimes[1]
            atime = datetimes[2]
            # handle datetime.datetime parameters
            if isinstance( ctime, datetime.datetime ) :
                ctime = time.mktime( ctime.timetuple() ) 
            if isinstance( mtime, datetime.datetime ) :
                mtime = time.mktime( mtime.timetuple() ) 
            if isinstance( atime, datetime.datetime ) :
                atime = time.mktime( atime.timetuple() )             
            # adjust for day light savings     
            now = time.localtime()
            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)            
            # change time stamps
            winfile = win32file.CreateFile(
                filePath, win32con.GENERIC_WRITE,
                win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE | win32con.FILE_SHARE_DELETE,
                None, win32con.OPEN_EXISTING,
                win32con.FILE_ATTRIBUTE_NORMAL, None)
            win32file.SetFileTime( winfile, ctime, atime, mtime )
            winfile.close()
        else : """MUST FIGURE OUT..."""
    except : pass    
Share:
40,192
Claudiu
Author by

Claudiu

Graduated from Brown University. E-mail: [email protected]

Updated on July 09, 2022

Comments

  • Claudiu
    Claudiu almost 2 years

    How do I change the file creation date of a Windows file from Python?

    • jfs
      jfs about 13 years
      modification, access times could be changed by os.utime() docs.python.org/library/os.html#os.utime
    • Claudiu
      Claudiu about 13 years
      @Sebastian: thanks for the links. i looked at the SO questions, they said there no platform-independent way to do it as for example linux doesn't store file creation times
    • Claudiu
      Claudiu about 13 years
      @David: hah nice, i'll remember that. what do you do for comments?
    • jfs
      jfs about 13 years
      @Claudiu: I've posted it for readers who search google for "python change file date windows". Your question is the second link.
    • Claudiu
      Claudiu about 13 years
      @Sebastian: ah got it, makes sense
    • Tobias Kienzler
      Tobias Kienzler over 9 years
      Same question for Linux: stackoverflow.com/q/887557/321973
  • netvope
    netvope about 13 years
    If you get an ImportError and wonder where you could find pywintypes (as I did): sourceforge.net/projects/pywin32
  • JJC
    JJC about 12 years
    Unfortunately, I'm pretty sure this only changes the file modification time and access time, not the file creation time, as the OP desires.
  • Ethan Furman
    Ethan Furman about 12 years
    On XP at least it sets the creation time.
  • Ethan Furman
    Ethan Furman about 12 years
    @Delta's solution is much simpler.
  • SilverbackNet
    SilverbackNet almost 12 years
    Doesn't do anything on XP or Win7 for me, the atime sets accesstime and mtime sets modifiedtime, neither sets creationtime.
  • Vlad
    Vlad about 7 years
    Error using python 3: type object 'datetime.datetime' has no attribute 'datetime'
  • panda-34
    panda-34 about 7 years
    @Vlad it's an error using incorrect import statements. The object is datetime.datetime as in my example, not datetime.datetime.datetime as you're trying to use it.
  • Vlad
    Vlad about 7 years
    you're right - I've change the import statement but now the error is a float is required for datetime.datetime.utcfromtimestamp(newtime). It would be great to have this work in python 3.
  • Mark Ransom
    Mark Ransom over 5 years
    Why is it so hard to find out that win32file is part of pywin32? Google left me high and dry, which meant none of the other answers were at all useful; they assumed you already had it installed. Thank you for the helpful hint at the top of your answer.
  • Mark Ransom
    Mark Ransom over 5 years
    P.S. Anybody who needs a timestamp from a datetime object can find the answer here: stackoverflow.com/q/7852855/5987
  • Tomasz Gandor
    Tomasz Gandor about 5 years
    For directories: see here: stackoverflow.com/questions/4998814/… !
  • Tomachi
    Tomachi over 4 years
    I like this "yak shaving" indeed this feels like what I am trying to do to support the Wintendo operating system. :)
  • Bruce Dawson
    Bruce Dawson over 4 years
    This code would be more useful if the meanings of the magic numbers were explained. My guesses are: - epoch is time in seconds? Since when? Maybe it doesn't matter? - 10000000 is a conversion factor between seconds and WIndows' 100 ns time units - 116444736000000000 is, well, I have no idea. It seems to be a time span of ~369 years, but I can't really tell.
  • Delgan
    Delgan over 4 years
    @BruceDawson This comes from the Microsoft documentation: How To Convert a UNIX time_t to a Win32 FILETIME or SYSTEMTIME.
  • Bruce Dawson
    Bruce Dawson over 4 years
    Thanks. That helps give context to the meaning of some of the magic numbers. It would still be good to document them in your answer, including the still unexplained 1561675987.509 number, which I guess is just a randomly selected time?
  • Delgan
    Delgan over 4 years
    @BruceDawson Sure, I added some comments to the code snippet. ;)
  • Eryk Sun
    Eryk Sun over 3 years
    GENERIC_WRITE requests data access that's not required here and either may not be granted by the file security or may lead to a sharing violation if an existing open doesn't share write-data access. The operation should only request FILE_WRITE_ATTRIBUTES metadata access, for which no data-access sharing is required, e.g. hfile = win32file.CreateFile(fname, ntsecuritycon.FILE_WRITE_ATTRIBUTES, 0, None, win32con.OPEN_EXISTING, 0, None).
  • Eryk Sun
    Eryk Sun over 3 years
    The project on GitHub should be updated to use kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) and raise exceptions via raise ctypes.WinError(ctypes.get_last_error()). This (1) isolates it from other packages that use the global library loader ctypes.windll, which caches loaded libraries, which cache function pointers, and (2) reliably captures the thread's last error value in C immediately after the FFI call.
  • Delgan
    Delgan over 3 years
    Thanks for your suggestion @ErykSun, I will make the update whenever I have some time (otherwise feel free to open a PR). Please, can you explain me why should I explicitly call ctypes.get_last_error() while raising a WinError()? Reading the documentation, I thought GetLastError() was automatically called anyway.
  • Eryk Sun
    Eryk Sun over 3 years
    Using ctypes to call GetLastError() via FFI leaves a lot of executed code between the original FFI call and the GetLastError() FFI call -- since Python is an interpreted scripting language. Loading the DLL with use_last_error=True automatically configures all function pointers created from it (e.g. kernel32.CreateFileW) to use a thread-local variable to set and capture the value of GetLastError() in C before and after the FFI call. ctypes.get_last_error() returns this thread-local last error value, and ctypes.set_last_error(error_code) sets it.
  • Delgan
    Delgan over 3 years
    @ErykSun I think I got it, thanks a lot for the clarification! I will update win32-setctime as soon as possible.
  • Roger Heathcote
    Roger Heathcote almost 3 years
    This is super useful, thank you for making and explaining it.
  • Zertrin
    Zertrin about 2 years
    I used it today, and it worked well for my use case. Thanks for making it and sharing it!