tags:

views:

492

answers:

2

Python's os.path.getctime on the Mac (and under Unix in general) does not give the date when a file was created but "the time of the last change" (according to the docs at least). On the other hand in the Finder I can see the real file creation time so this information is kept by HFS+.

Do you have any suggestions on how to obtain the file creation time on the Mac in a Python program?

A: 

ctime differs on the platform: On some systems (like Unix) is the time of the last metadata change, and, on others (like Windows), is the creation time. That's because Unices usually don't preserve the "original" creation time.

That said you can access all information that the OS provides with the stat module.

The stat module defines constants and functions for interpreting the results of os.stat(), os.fstat() and os.lstat() (if they exist). For complete details about the stat, fstat and lstat calls, consult the documentation for your system.

stat.ST_CTIME
The “ctime” as reported by the operating system. On some systems (like Unix) is the time of the last metadata change, and, on others (like Windows), is the creation time (see platform documentation for details).

lothar
Thanks but... stat.ST_CTIME: The “ctime” as reported by the operating system. On some systems (like Unix) is the time of the last metadata change, and, on others (like Windows), is the creation time (see platform documentation for details).
cefstat
@cefstat That's the point. Some systems (like unices) simply do _not_ provide the "original" creation time. There's nothing python can do about that.
lothar
+3  A: 

Using ctypes to access the system call stat64 (works with Python 2.5+):

from ctypes import *

class struct_timespec(Structure):
    _fields_ = [('tv_sec', c_long), ('tv_nsec', c_long)]

class struct_stat64(Structure):
    _fields_ = [
        ('st_dev', c_int32),
        ('st_mode', c_uint16),
        ('st_nlink', c_uint16),
        ('st_ino', c_uint64),
        ('st_uid', c_uint32),
        ('st_gid', c_uint32), 
        ('st_rdev', c_int32),
        ('st_atimespec', struct_timespec),
        ('st_mtimespec', struct_timespec),
        ('st_ctimespec', struct_timespec),
        ('st_birthtimespec', struct_timespec),
        ('dont_care', c_uint64 * 8)
    ]

libc = CDLL('libc.dylib')
stat64 = libc.stat64
stat64.argtypes = [c_char_p, POINTER(struct_stat64)]

def get_creation_time(path):
    buf = struct_stat64()
    rv = stat64(path, pointer(buf))
    if rv != 0:
        raise OSError("Couldn't stat file %r" % path)
    return buf.st_birthtimespec.tv_sec


Using subprocess to call the stat utility:

import subprocess

def get_creation_time(path):
    p = subprocess.Popen(['stat', '-f%B', path],
        stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    if p.wait():
        raise OSError(p.stderr.read().rstrip())
    else:
        return int(p.stdout.read())


You can convert the integer result to a datetime object using datetime.datetime.fromtimestamp().

Miles
Perfect! This is exactly what I was looking for.
cefstat