ChatGPT解决这个技术问题 Extra ChatGPT

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

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

You can't get file creation time in a cross-platform way. See docs.python.org/library/os.path.html#os.path.getctime
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?
@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.
@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.
@questionto42 totally agreed, I'm aware of the differences and I was trying to be brief, you clarified it better than I did.

i
igracia

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:

On Windows, a file's ctime (documented at https://msdn.microsoft.com/en-us/library/14h5k7ff.aspx) stores its creation date. You can access this in Python through os.path.getctime() or the .st_ctime attribute of the result of a call to os.stat(). This won't work on Unix, where the ctime is the last time that the file's attributes or content were changed.

On Mac, as well as some other Unix-based OSes, you can use the .st_birthtime attribute of the result of a call to os.stat().

On Linux, this is currently impossible, at least without writing a C extension for Python. Although some file systems commonly used with Linux do store creation dates (for example, ext4 stores them in st_crtime) , the Linux kernel offers no way of accessing them; in particular, the structs it returns from stat() calls in C, as of the latest kernel version, don't contain any creation date fields. You can also see that the identifier st_crtime doesn't currently feature anywhere in the Python source. At least if you're on ext4, the data is attached to the inodes in the file system, but there's no convenient way of accessing it. The next-best thing on Linux is to access the file's mtime, through either os.path.getmtime() or the .st_mtime attribute of an os.stat() result. This will give you the last time the file's content was modified, which may be adequate for some use cases.

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 http://stackoverflow.com/a/39501288/1709587 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

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.
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.
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.
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? Cheers
@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 stackoverflow.com/a/39521489/1709587 where I provide some example code to illustrate this.
P
Peter Mortensen

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.)


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.
Keep in mind the first example gives you a string, not a datetime or number.
@kojiro 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!
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!
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 why
P
Peter Mortensen

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)

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.
@MarkAmery - This answer is clearly labeled as just being about modification time.
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.
S
Steven C. Howell

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.


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.
P
Peter Mortensen

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).


os.path.getmtime() is made for this, and simpler.
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.
P
Puddle
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".


@ntninja 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)
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 )
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.
@ntninja 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.
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.
C
Community

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.


M
Mr_and_Mrs_D

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.


Here is more about tagged-tuples: stackoverflow.com/questions/2970608/… They work like tuples, but try dir(..) on one. E.g. dir(os.stat(os.listdir('.')[0]))
D
Delgan

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

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…)
@ntninja I would probably never use in in production neither, but it may be useful for "home scripting".
Yea, agreed. I created this for the really desperate.
u
unmounted
>>> import os
>>> os.stat('feedparser.py').st_mtime
1136961142.0
>>> os.stat('feedparser.py').st_ctime
1222664012.233
>>> 

-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!).
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?
P
Peter Mortensen

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

This will give the time of last read (at least on Unix), which definitely isn't what was asked for.
What do you mean by "...symbolic links are not important"? Can you elaborate?
R
Rod

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.


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.stat
Please use .st_ctime instead of ugly numbers [8].