views:

276

answers:

2

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.

A: 
JimB
For the most part, those HFS+ attributes map to the equivalent POSIX stat() attributes. contentModDate is the same as mtime, attributeModDate is the same as ctime, and accessDate is the same as atime.
mipadi
@mipadi - you may have commented before my edit was posted, but, yes I know ;) Unfortunately the OP is looking at createDate through Finder, which isn't mapped to a POSIX attribute
JimB
+1  A: 

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" && ptyhon 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.

Chris Johnsen