How do I get file creation and modification date/times?
Asked Answered
B

13

1318

What's the best cross-platform way to get file creation and modification dates/times, that works on both Linux and Windows?

Brightman answered 25/10, 2008 at 21:54 Comment(5)
You can't get file creation time in a cross-platform way. See docs.python.org/library/os.path.html#os.path.getctimeVeolaver
Mind that the accepted answer is not recommended anymore, use pathlib instead of os, see @StevenC.Howell's answer. Perhaps one could even change the accepted answer to the pathlib answer?Emmettemmey
@questionto42, while I agree, it might pay to give a reason why you advise that. Just from looking at this SO post, many would see (from @StephenCHowell's answer) that pathlib is wrapping os, and then ask what's the point in using pathlib then? The answer, as I understand it, is that pathlib has a smaller namespace than os and generally results in cleaner code.Inextricable
@Jlanger I wrote this because I had awkward code with os for complex recursions + path checking + file name replacing over a larger file system until I found pathlib. Pathlib is easier and cleaner - I even remember it was more powerful due to its Path objects, thus, more pythonic. Smaller namespace is not the point. It is dangerous if a strongly used Q/A like this spreads older ways of programming, I took os and wasted time and nerves, therefore the comment. You can find more of pathlib vs. os with a quick internet search.Emmettemmey
@Emmettemmey totally agreed, I'm aware of the differences and I was trying to be brief, you clarified it better than I did.Inextricable
T
190

In Python 3.4 and above, you can use the object oriented pathlib module interface which includes wrappers for much of the os module. Here is an example of getting the file stats.

>>> import pathlib
>>> fname = pathlib.Path('test.py')
>>> assert fname.exists(), f'No such file: {fname}'  # check that the file exists
>>> print(fname.stat())
os.stat_result(st_mode=33206, st_ino=5066549581564298, st_dev=573948050, st_nlink=1, st_uid=0, st_gid=0, st_size=413, st_atime=1523480272, st_mtime=1539787740, st_ctime=1523480272)

For more information about what os.stat_result contains, refer to the documentation. For the modification time you want fname.stat().st_mtime:

>>> import datetime
>>> mtime = datetime.datetime.fromtimestamp(fname.stat().st_mtime, tz=datetime.timezone.utc)
>>> print(mtime)
datetime.datetime(2018, 10, 17, 10, 49, 0, 249980)

If you want the creation time on Windows, or the most recent metadata change on Unix, you would use fname.stat().st_ctime:

>>> ctime = datetime.datetime.fromtimestamp(fname.stat().st_ctime, tz=datetime.timezone.utc)
>>> print(ctime)
datetime.datetime(2018, 4, 11, 16, 57, 52, 151953)

This article has more helpful info and examples for the pathlib module.

Triiodomethane answered 17/10, 2018 at 15:5 Comment(1)
I strongly recommend, as also mentioned with the previous anwser, using datetime.datetime.fromtimestamp(t, tz=datetime.timezone.utc) here, as the naive datetime object returned otherwise has a tendency to be interpreted as being in the local timezone instead while Unix timestamps are always relative to the 01.01.1970 00:00 UTC.Fatwitted
H
916

Getting some sort of modification date in a cross-platform way is easy - just call os.path.getmtime(path) and you'll get the Unix timestamp of when the file at path was last modified.

Getting file creation dates, on the other hand, is fiddly and platform-dependent, differing even between the three big OSes:

Putting this all together, cross-platform code should look something like this...

import os
import platform

def creation_date(path_to_file):
    """
    Try to get the date that a file was created, falling back to when it was
    last modified if that isn't possible.
    See https://mcmap.net/q/45386/-how-do-i-get-file-creation-and-modification-date-times for explanation.
    """
    if platform.system() == 'Windows':
        return os.path.getctime(path_to_file)
    else:
        stat = os.stat(path_to_file)
        try:
            return stat.st_birthtime
        except AttributeError:
            # We're probably on Linux. No easy way to get creation dates here,
            # so we'll settle for when its content was last modified.
            return stat.st_mtime
Haematinic answered 14/9, 2016 at 23:51 Comment(10)
I've done my best to throw this together (and spent a few hours researching in the process), and I'm sure it's at least more correct than the answers that were here previously, but this is a really hard topic and I'd appreciate any corrections, clarifications, or other input that people can offer. In particular, I'd like to construct a way of accessing this data on ext4 drives under Linux, and I'd like to learn what happens when Linux reads files written by Windows, or vica versa, given that they use st_ctime differently.Haematinic
Frankly, file creation time is usually fairly useless. When you open an existing file for write with mode "w", it's not replacing it, it just opens the existing file and truncates it. Even though the file contents are completely unrelated to whatever it had on creation, you'd still be told the file was "created" well before the current version. Conversely, editors that use atomic replace on save (original file is replaced by new work-in-progress temp file) would show a more recent creation date, even if you just deleted one character. Use the modification time, don't grub for creation time.Aircrew
After many years, I've finally found a use for file creation time! I'm writing code to check a file naming convention in certain directories, so first of all I want to consider files that were first named after the convention was instituted. Replacing the entire contents (mtime) is irrelevant: if it was already there then it's grandfathered in.Khmer
Hi Mark. I propose a simplification. On Linux, returning stat.st_ctime is more pertinent because, in many cases, the time of last metadata change can be the creation time (at least ctime is closer to the real creation time than mtime). Therefore, you could simply replace your snippet by stat = os.stat(path_to_file); try: return stat.st_birthtime; except AttributeError: return stat.st_ctime. What do you think? CheersMethane
@olibre "at least ctime is closer to the real creation time than mtime" - no it isn't; this is something I've seen stated several times but it's totally false. Unless you've manually messed with the values in your inode, ctime should always be equal to or later than mtime, because an mtime change causes a ctime change (because the mtime itself is considered "metadata"). See https://mcmap.net/q/46455/-is-ctime-always-lt-mtime where I provide some example code to illustrate this.Haematinic
Whenever st_ctime comes up, we need these ugly wart disclaimers about the different meaning in Windows, and this makes for ugly code even if the ctime is rarely used. I'd like to change the Windows implementation of os.stat to support st_birthtime in addition to st_ctime, but deprecate using st_ctime as the "creation time". An environment variable would allow using st_ctime as the change time (supported by NTFS; we'd have to modify the queries used to implement os.stat), which would subsequently be made the default in the next version.Openwork
If the files are images, you can also get try to get the taken date usin PIL: ` from PIL import Image def get_date_taken(path): try: return Image.open(path)._getexif()[36867] except: return os.path.getmtime(path) `Dix
Note that the statement “Although some file systems commonly used with Linux do store creation dates […], the Linux kernel offers no way of accessing them” is not true anymore since Linux 4.11: The statx system call does allow querying btime if available for the given file. (This is not used/exposed even in Python 3.8 however.)Fatwitted
One could use something like int(subprocess.check_output(["stat", "--printf", "%W", path_to_file])) to get the creation/birth date in linux.Impeller
Look at the st_ctime updates for Windows from Python 3.12: docs.python.org/3.12/library/os.html#os.stat_result.st_ctimePrelacy
L
786

You have a couple of choices. For one, you can use the os.path.getmtime and os.path.getctime functions:

import os.path, time
print("last modified: %s" % time.ctime(os.path.getmtime(file)))
print("created: %s" % time.ctime(os.path.getctime(file)))

Your other option is to use os.stat:

import os, time
(mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(file)
print("last modified: %s" % time.ctime(mtime))

Note: ctime() does not refer to creation time on *nix systems, but rather the last time the inode data changed. (Thanks to kojiro for making that fact more clear in the comments by providing a link to an interesting blog post.)

Lactate answered 25/10, 2008 at 22:0 Comment(5)
Just in case anyone misses @Glyph's comment to the question, ctime does not mean creation time on POSIX systems. I wonder how many people have skimmed this post over the past three years and gone on to write buggy code.Priestly
Keep in mind the first example gives you a string, not a datetime or number.Cornelison
@Priestly the blog post you've linked to could be more explicit that on Unix a file's ctime gets updated whenever the mtime does (since the mtime is "metadata"), and so the ctime is normally always equal to or ahead of the mtime. Treating ctime as "created" time thus makes no sense at all. -1!Haematinic
Your first option returns the same results for both file creation and last modification! Last modified: Fri Jan 31 11:08:13 2020 and Created: Fri Jan 31 11:08:13 2020 on Linux Ubuntu 16.04!Tetzel
I discover that time.ctime(os.path.getmtime(file)) returns 2 types of strings, depending if the file has been modified by the system or by the user. If it has been modified by the system the string will have 2 spaces between the month and the day. I don't know whyWheedle
D
436

The best function to use for this is os.path.getmtime(). Internally, this just uses os.stat(filename).st_mtime.

The datetime module is the best for manipulating timestamps, so you can get the modification date as a datetime object like this:

import os
import datetime
def modification_date(filename):
    t = os.path.getmtime(filename)
    return datetime.datetime.fromtimestamp(t)

Usage example:

>>> d = modification_date('/var/log/syslog')
>>> print d
2009-10-06 10:50:01
>>> print repr(d)
datetime.datetime(2009, 10, 6, 10, 50, 1)
Dosi answered 6/10, 2009 at 14:51 Comment(3)
This answer is also a little bit wrong. getmtime is the nearest thing available on Unix (where getting creation dates isn't possible), but is definitely not the best function to use on Windows, where the ctime is a creation time.Haematinic
@MarkAmery - This answer is clearly labeled as just being about modification time.Sheree
I strongly recommend using datetime.datetime.fromtimestamp(t, tz=datetime.timezone.utc) here, as the naive datetime object returned otherwise has a tendency to be interpreted as being in the local timezone instead while Unix timestamps are always relative to the 01.01.1970 00:00 UTC.Fatwitted
T
190

In Python 3.4 and above, you can use the object oriented pathlib module interface which includes wrappers for much of the os module. Here is an example of getting the file stats.

>>> import pathlib
>>> fname = pathlib.Path('test.py')
>>> assert fname.exists(), f'No such file: {fname}'  # check that the file exists
>>> print(fname.stat())
os.stat_result(st_mode=33206, st_ino=5066549581564298, st_dev=573948050, st_nlink=1, st_uid=0, st_gid=0, st_size=413, st_atime=1523480272, st_mtime=1539787740, st_ctime=1523480272)

For more information about what os.stat_result contains, refer to the documentation. For the modification time you want fname.stat().st_mtime:

>>> import datetime
>>> mtime = datetime.datetime.fromtimestamp(fname.stat().st_mtime, tz=datetime.timezone.utc)
>>> print(mtime)
datetime.datetime(2018, 10, 17, 10, 49, 0, 249980)

If you want the creation time on Windows, or the most recent metadata change on Unix, you would use fname.stat().st_ctime:

>>> ctime = datetime.datetime.fromtimestamp(fname.stat().st_ctime, tz=datetime.timezone.utc)
>>> print(ctime)
datetime.datetime(2018, 4, 11, 16, 57, 52, 151953)

This article has more helpful info and examples for the pathlib module.

Triiodomethane answered 17/10, 2018 at 15:5 Comment(1)
I strongly recommend, as also mentioned with the previous anwser, using datetime.datetime.fromtimestamp(t, tz=datetime.timezone.utc) here, as the naive datetime object returned otherwise has a tendency to be interpreted as being in the local timezone instead while Unix timestamps are always relative to the 01.01.1970 00:00 UTC.Fatwitted
W
57
import os, time, datetime

file = "somefile.txt"
print(file)

print("Modified")
print(os.stat(file)[-2])
print(os.stat(file).st_mtime)
print(os.path.getmtime(file))

print()

print("Created")
print(os.stat(file)[-1])
print(os.stat(file).st_ctime)
print(os.path.getctime(file))

print()

modified = os.path.getmtime(file)
print("Date modified: "+time.ctime(modified))
print("Date modified:",datetime.datetime.fromtimestamp(modified))
year,month,day,hour,minute,second=time.localtime(modified)[:-3]
print("Date modified: %02d/%02d/%d %02d:%02d:%02d"%(day,month,year,hour,minute,second))

print()

created = os.path.getctime(file)
print("Date created: "+time.ctime(created))
print("Date created:",datetime.datetime.fromtimestamp(created))
year,month,day,hour,minute,second=time.localtime(created)[:-3]
print("Date created: %02d/%02d/%d %02d:%02d:%02d"%(day,month,year,hour,minute,second))

prints

somefile.txt
Modified
1429613446
1429613446.0
1429613446.0

Created
1517491049
1517491049.28306
1517491049.28306

Date modified: Tue Apr 21 11:50:46 2015
Date modified: 2015-04-21 11:50:46
Date modified: 21/04/2015 11:50:46

Date created: Thu Feb  1 13:17:29 2018
Date created: 2018-02-01 13:17:29.283060
Date created: 01/02/2018 13:17:29

Note: A file's ctime on Linux is slightly different than on Windows.
Windows users know theirs as "creation time".
Linux users know theirs as "change time".

Whitley answered 3/12, 2018 at 2:59 Comment(11)
@Fatwitted are you sure about that? i only use Windows and this absolutely works. i wrote this script in early 2015. i find it was more clear, straight to the point, complete and self explanatory than others here. (which i happened to decide to look up here instead of my old scripts just incase there was anything new. nope... this is the way)Whitley
Oh, I meant to say “… this will not give you the file's creation time, unless you are on Windows”. Sorry! Fact remains that this answer is not portable and doesn't mention this fact. (Example output on Linux: pastebin.com/50r5vGBE )Fatwitted
Already left some other comments here and I'll post an answer that works on (recent) Linux as well soon. But really, the only thing wrong in your post is that it's Windows-only answer that doesn't mention this fact. In the question OP even specifically asked for a Windows and Linux compatible solution. As such I think it would be very helpful if you added this “detail” somewhere at the top, so that people aren't mislead into thinking ctime is what they're looking when targeting multiple platforms.Fatwitted
@Fatwitted I just realized you were wrong to blame me (and others) over ctime. What you really meant to point out is that a file's ctime on linux is slightly different than on windows. But if you're programming for linux users you wouldn't be trying to provide info from a windows perspective anyway. Same way you wouldn't try provide the linux equivalent to windows users. That's like complaining you can't open cmd on linux, that it opens its version of it. lol (And surely there's a reason such crossplatform function even exists) But besides that, mtime is what's most significant to anyone anyway.Whitley
It isn’t “slightly different” on Windows vs Unix – it’s completely different: Unless you manually update the values, on Windows ctime <= mtime always holds while, in complete opposition, on Unix mtime <= ctime always holds. Your answer suggests that ctime is the “Date created” of the file, without any suggestion that this doesn’t portably hold at all. Had you called it “Date created (on Windows)” or said “This answer only applies to Windows” at the top it would be very different, but that’s not what you are doing event after your (still appreciated) update of your answer.Fatwitted
Also your ad hominem statement “if you're programming for linux users you wouldn't be trying to provide info from a windows perspective anyway” is completely false as I, assuming I am aware of respective issue, would definitely point this out in code review and teaching if there is ever any chance that the resulting may be run cross-platform (i.e. just about always). <sarcasm>After all, the person in question may have would up on StackOverflow after searching for “file creation time” and gone “oh the C in ctime is for creation” after quickly skimming over your answer.</sarcasm>Fatwitted
Considering the question explicitly states it has to work on multiple OS, it seems important to keep those details correct.Crater
@Fatwitted So are we saying the person who implemented os.path.getctime(file) in python implemented it wrong on linux? That's who you might as well be arguing with. And if something ain't possible on linux/windows, you clearly wouldn't. Otherwise please tell me how we get linux's "change time" on windows.Whitley
@Crater I agree it's worth pointing out. (hence i edited my answer) But one half of the answer is still correct. Before i thought he was telling me my whole answer was wrong.Whitley
@Puddle: No they did not, it’s just an unfortunate fact that we have a field named ctime in the stat results whose meaning is entirely different depending on platform, quoting straight from the docs of os.path.getctime: Return the system’s ctime which, on some systems (like Unix) is the time of the last metadata change, and, on others (like Windows), is the creation time for path.Fatwitted
@Fatwitted If there's a cross platform solution, then it makes no sense the function is inconsistant. If there isn't a cross platform solution (explaining the reasonable/expected alternative), then that's the answer. You just can't. Just like the very first reply to the question answered. "You can't get file creation time in a cross-platform way. See os.path.getctime"Whitley
D
48

os.stat

In newer code you should probably use os.path.getmtime() (thanks, Christian Oudard).

But note that it returns a floating point value of time_t with fraction seconds (if your OS supports it).

Dune answered 25/10, 2008 at 21:58 Comment(2)
os.path.getmtime() is made for this, and simpler.Dosi
The "in newer code" clause here is a bit misleading. os.path.getmtime() has been around since Python 1.5.2 (see the old docs), released before I'd lost most of my baby teeth and almost a decade before you wrote the original version of this answer.Haematinic
N
46

There are two methods to get the mod time, os.path.getmtime() or os.stat(), but the ctime is not reliable cross-platform (see below).

os.path.getmtime()

getmtime(path)
Return the time of last modification of path. The return value is a number giving the number of seconds since the epoch (see the time module). Raise os.error if the file does not exist or is inaccessible. New in version 1.5.2. Changed in version 2.3: If os.stat_float_times() returns True, the result is a floating point number.

os.stat()

stat(path)
Perform a stat() system call on the given path. The return value is an object whose attributes correspond to the members of the stat structure, namely: st_mode (protection bits), st_ino (inode number), st_dev (device), st_nlink (number of hard links), st_uid (user ID of owner), st_gid (group ID of owner), st_size (size of file, in bytes), st_atime (time of most recent access), st_mtime (time of most recent content modification), st_ctime (platform dependent; time of most recent metadata change on Unix, or the time of creation on Windows):

>>> import os
>>> statinfo = os.stat('somefile.txt')
>>> statinfo
(33188, 422511L, 769L, 1, 1032, 100, 926L, 1105022698,1105022732, 1105022732)
>>> statinfo.st_size
926L
>>> 

In the above example you would use statinfo.st_mtime or statinfo.st_ctime to get the mtime and ctime, respectively.

Novocaine answered 25/10, 2008 at 22:5 Comment(0)
L
13

os.stat returns a named tuple with st_mtime and st_ctime attributes. The modification time is st_mtime on both platforms; unfortunately, on Windows, ctime means "creation time", whereas on POSIX it means "change time". I'm not aware of any way to get the creation time on POSIX platforms.

Lily answered 25/10, 2008 at 22:6 Comment(1)
Here is more about tagged-tuples: #2971108 They work like tuples, but try dir(..) on one. E.g. dir(os.stat(os.listdir('.')[0]))Pithecanthropus
R
2

It may worth taking a look at the crtime library which implements cross-platform access to the file creation time.

from crtime import get_crtimes_in_dir

for fname, date in get_crtimes_in_dir(".", raise_on_error=True, as_epoch=False):
    print(fname, date)
    # file_a.py Mon Mar 18 20:51:18 CET 2019
Roshan answered 25/10, 2008 at 21:55 Comment(3)
I strongly advise against this: It uses debugfs on Linux which is by definition unstable, requires top-level root access for everything and in pretty much every aspect tends to be one of the things your mother always warned you about. (But yes, it probably works if you're really desperate and happen to be the real superuser on a system without secure boot…)Fatwitted
@Fatwitted I would probably never use in in production neither, but it may be useful for "home scripting".Roshan
Yea, agreed. I created this for the really desperate.Fridge
J
2

I am a fan of pathlib.

from pathlib import Path

target = Path('out/soong/build.ninja')
mtime = target.stat().st_mtime
atime = target.stat().st_atime
ctime = target.stat().st_ctime

I believe this is also feasible for Windows Subsystem for Linux (WSL).

Jackpot answered 3/3, 2023 at 2:45 Comment(1)
It is my understanding that when you instantiate a pathlib.Path object, it automatically represents the OS specific implementation. And since these implementations inherit from pathlib.Path, the function/properties you list are available on on any OS, not only Windows or the WSL.Lamartine
S
1
>>> import os
>>> os.stat('feedparser.py').st_mtime
1136961142.0
>>> os.stat('feedparser.py').st_ctime
1222664012.233
>>> 
Sycophancy answered 25/10, 2008 at 22:7 Comment(2)
-1: As mentioned elsewhere this will not give you the file's creation time, unless you are on Windows (which the answer does not even mention!).Fatwitted
An explanation would be in order. E.g., what do we see? What do the results tell us? What is the conclusion? On which platform was this tested? What version of Python and of libraries? Can you link to documentation for the used properties?Lycaon
I
0

If the following symbolic links are not important, you can also use the os.lstat builtin.

>>> os.lstat("2048.py")
posix.stat_result(st_mode=33188, st_ino=4172202, st_dev=16777218L, st_nlink=1, st_uid=501, st_gid=20, st_size=2078, st_atime=1423378041, st_mtime=1423377552, st_ctime=1423377553)
>>> os.lstat("2048.py").st_atime
1423378041.0
Ingenuous answered 11/2, 2015 at 0:13 Comment(2)
This will give the time of last read (at least on Unix), which definitely isn't what was asked for.Haematinic
What do you mean by "...symbolic links are not important"? Can you elaborate?Lycaon
P
-2

os.stat does include the creation time. There's just no definition of st_anything for the element of os.stat() that contains the time.

So try this:

os.stat('feedparser.py')[8]

Compare that with your create date on the file in ls -lah

They should be the same.

Possessory answered 14/12, 2008 at 23:39 Comment(2)
Wrong! os.stat('feedparser.py')[8] refers to st_mtime, not creation time. Please refer to the documentation: docs.python.org/library/os.html#os.statWaterage
Please use .st_ctime instead of ugly numbers [8].Collectivity

© 2022 - 2024 — McMap. All rights reserved.