Question

I'm having trouble using os.utime to correctly set the modification time on the mac (Mac OS X 10.6.2, running Python 2.6.1 from /usr/bin/python). It's not consistent with the touch utility, and it's not consistent with the properties displayed in the Finder's "get info" window.

Consider the following command sequence. The 'created' and 'modified' times in the plain text refer to the attributes shown in the "get info" window in the finder. As a reminder, os.utime takes arguments (filename, (atime, mtime)).

>>> import os
>>> open('tempfile','w').close()

'created' and 'modified' are both the current time.

>>> os.utime('tempfile', (1000000000, 1500000000) )

'created' is the current time, 'modified' is July 13, 2017.

>>> os.utime('tempfile', (1000000000, 1000000000) )

'created' and 'modified' are both September 8, 2001.

>>> os.path.getmtime('tempfile')
1000000000.0
>>> os.path.getctime('tempfile')
1269021939.0
>>> os.path.getatime('tempfile')
1269021951.0

...but the os.path.get?time and os.stat don't reflect it.

>>> os.utime('tempfile', (1500000000, 1000000000) )

'created' and 'modified' are still both September 8, 2001.

>>> os.utime('tempfile', (1500000000, 1500000000) )

'created' is September 8, 2001, 'modified' is July 13, 2017.

I'm not sure if this is a Python problem or a Mac stat problem. When I exit the Python shell and run

touch -a -t 200011221234 tempfile

neither the modification nor the creation times are changed, as expected. Then I run

touch -m -t 200011221234 tempfile

and both 'created' and 'modified' times are changed.

Does anyone have any idea what's going on? How do I change the modification and creation times consistently on the mac? (Yes, I am aware that on Unixy systems there is no "creation time.")


Result from running Chris Johnsen's script:

seth@local:~$ /usr/bin/python timetest.py tempfile 5
initial:
(1269631281.0, 1269631281.0, 1269631281.0, 1269631281, 1269631281, 1269631281)

test: (1000000000, 1000000000)
(1000000000.0, 1000000000.0, 1269631281.0, 1000000000, 1000000000, 1269631281)
(1269631281.0, 1000000000.0, 1269631281.0, 1269631281, 1000000000, 1269631281)

test: (1000000000, 1500000000)
(1000000000.0, 1500000000.0, 1269631286.0, 1000000000, 1500000000, 1269631286)
(1269631286.0, 1500000000.0, 1269631286.0, 1269631286, 1500000000, 1269631286)

test: (1500000000, 1000000000)
(1500000000.0, 1000000000.0, 1269631291.0, 1500000000, 1000000000, 1269631291)
(1269631291.0, 1000000000.0, 1269631291.0, 1269631291, 1000000000, 1269631291)

test: (1500000000, 1500000000)
(1500000000.0, 1500000000.0, 1269631296.0, 1500000000, 1500000000, 1269631296)
(1269631296.0, 1500000000.0, 1269631296.0, 1269631296, 1500000000, 1269631296)

At the end of the exercise, the 'created' date as visible in the finder is 9/8/01 and the 'modified' date is 7/13/17. (The access date, thanks to presumably spotlight as you suggest and as I've read about, is roughly 'now.') The created and modified dates visible in the finder still make no sense.

Was it helpful?

Solution

POSIX atime, mtime, ctime

It might help if you included a full script and its actual and expected outputs instead of the REPL fragments.

import sys, os, stat, time

def get_times(p):
    s = os.stat(p)
    return ( 
        os.path.getatime(p),
        os.path.getmtime(p),
        os.path.getctime(p),
        s[stat.ST_ATIME],
        s[stat.ST_MTIME],
        s[stat.ST_CTIME],
    )

def main(p, delay=1):
    delay = float(delay)
    (a,b) = (1000000000, 1500000000)

    open(p,'w').close()

    print 'initial:'
    print get_times(p)

    for t in [ (a,a), (a,b), (b,a), (b,b) ]:
        print
        print 'test:', t
        os.utime(p,t)
        print get_times(p)
        time.sleep(delay)
        print get_times(p)

main(*sys.argv[1:])

I get this on my 10.4 system with cd "$HOME" && python test.py tempfile 5 (system default Python 2.3.6 and MacPorts Python 2.6.4 both give the same result (leaving out the initial times and ctime, of course)):

% python /tmp/test.py tempfile 5
initial:
(1000000000.0, 1000000000.0, 1269629881.0, 1000000000, 1000000000, 1269629881)

test: (1000000000, 1000000000)
(1000000000.0, 1000000000.0, 1269629881.0, 1000000000, 1000000000, 1269629881)
(1000000000.0, 1000000000.0, 1269629881.0, 1000000000, 1000000000, 1269629881)

test: (1000000000, 1500000000)
(1000000000.0, 1500000000.0, 1269629886.0, 1000000000, 1500000000, 1269629886)
(1000000000.0, 1500000000.0, 1269629886.0, 1000000000, 1500000000, 1269629886)

test: (1500000000, 1000000000)
(1500000000.0, 1000000000.0, 1269629891.0, 1500000000, 1000000000, 1269629891)
(1500000000.0, 1000000000.0, 1269629891.0, 1500000000, 1000000000, 1269629891)

test: (1500000000, 1500000000)
(1500000000.0, 1500000000.0, 1269629896.0, 1500000000, 1500000000, 1269629896)
(1500000000.0, 1500000000.0, 1269629896.0, 1500000000, 1500000000, 1269629896)

That seems reasonable. I wonder what you get.

I have heard that Spotlight can sometimes aggressively reset atime due to re-indexing changed files. I would not expect it to re-index a file that has only undergone utime()/utimes(), but I suppose it is possible. To eliminate Spotlight as a possible complication use a file in a location that is not indexed by Spotlight (e.g. /tmp/testfile).

Date Created in Finder

(shown as “Created:” in Get Info windows of Finder)

If you have the Developer tools installed, you can use /Developer/Tools/GetFileInfo to see the HFS creationDate. I added the following lines after every print get_times(p) line:

sys.stdout.flush()
os.system('/Developer/Tools/GetFileInfo ' + p)

I also changed the iteration to match your initial description ([ (a,b), (a,a), (b,a), (b,b) ]).

The result now looks like this:

% rm /tmp/tempfile; python /tmp/test.py /tmp/tempfile 1
initial:
(1269636574.0, 1269636574.0, 1269636574.0, 1269636574, 1269636574, 1269636574)
file: "/private/tmp/tempfile"
type: ""
creator: ""
attributes: avbstclinmedz
created: 03/26/2010 15:49:34
modified: 03/26/2010 15:49:34

test: (1000000000, 1500000000)
(1000000000.0, 1500000000.0, 1269636574.0, 1000000000, 1500000000, 1269636574)
file: "/private/tmp/tempfile"
type: ""
creator: ""
attributes: avbstclinmedz
created: 03/26/2010 15:49:34
modified: 07/13/2017 21:40:00
(1000000000.0, 1500000000.0, 1269636574.0, 1000000000, 1500000000, 1269636574)
file: "/private/tmp/tempfile"
type: ""
creator: ""
attributes: avbstclinmedz
created: 03/26/2010 15:49:34
modified: 07/13/2017 21:40:00

test: (1000000000, 1000000000)
(1000000000.0, 1000000000.0, 1269636576.0, 1000000000, 1000000000, 1269636576)
file: "/private/tmp/tempfile"
type: ""
creator: ""
attributes: avbstclinmedz
created: 09/08/2001 20:46:40
modified: 09/08/2001 20:46:40
(1000000000.0, 1000000000.0, 1269636576.0, 1000000000, 1000000000, 1269636576)
file: "/private/tmp/tempfile"
type: ""
creator: ""
attributes: avbstclinmedz
created: 09/08/2001 20:46:40
modified: 09/08/2001 20:46:40

test: (1500000000, 1000000000)
(1500000000.0, 1000000000.0, 1269636577.0, 1500000000, 1000000000, 1269636577)
file: "/private/tmp/tempfile"
type: ""
creator: ""
attributes: avbstclinmedz
created: 09/08/2001 20:46:40
modified: 09/08/2001 20:46:40
(1500000000.0, 1000000000.0, 1269636577.0, 1500000000, 1000000000, 1269636577)
file: "/private/tmp/tempfile"
type: ""
creator: ""
attributes: avbstclinmedz
created: 09/08/2001 20:46:40
modified: 09/08/2001 20:46:40

test: (1500000000, 1500000000)
(1500000000.0, 1500000000.0, 1269636578.0, 1500000000, 1500000000, 1269636578)
file: "/private/tmp/tempfile"
type: ""
creator: ""
attributes: avbstclinmedz
created: 09/08/2001 20:46:40
modified: 07/13/2017 21:40:00
(1500000000.0, 1500000000.0, 1269636578.0, 1500000000, 1500000000, 1269636578)
file: "/private/tmp/tempfile"
type: ""
creator: ""
attributes: avbstclinmedz
created: 09/08/2001 20:46:40
modified: 07/13/2017 21:40:00

This seems to be consistent with your observations from your Get Info window in Finder. My interpretation (borne out by other experimentation) is that the HFS creationDate is updated by utime, but it only ever goes backwards (never forwards). If you want to update the HFS creationDate to a newer value, then you probably will have to use a Mac-specific API to do it.

One other note: you may have to switch windows a bit to get the Get Info window to update. On my system, its display does not automatically update unless I switch windows either to or from the Get Info window.

OTHER TIPS

Mac OS maintains extra attributes that don't map to posix.

  • createDate
  • contentModDate
  • attributeModDate
  • accessDate
  • backupDate

You used to be able to access these through the old macfs module, which was long ago deprecated in favor of the Carbon module, which is largely undocumented, and also now deprecated. I think Carbon.File and Carbon.Folder have what you need. (I don't follow Mac enough to know what the current plan is for these features. Maybe Carbon is just being pulled from the stdlib, and it will continue on it's own.)

Maybe a comment detailing what you're looking for would help, instead of a downvote

I'm not exactly sure what other consistency you expect. Python is using a posix api, and the Apple tools are using Apple's api. Each one seems to be internally consistent, but they can differ between each other.

  • attributeModDate is mapped to ctime.
  • createDate is what Finder displays for "created"
  • If you change mtime to earlier than createDate, the mac filesystem api will change the createDate to match; which prevents the inconsistency of an apparent modification before a creation. This addresses the only inconsistent behavior I can gather from your example above.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top