The following script works correctly (?) on my Mac.
Last_Opened_OF(choose file) --> date "Sunday, 16 April 2023 - 6:00:51 PM"
on Last_Opened_OF(theAlias)
set iso8601Text to do shell script "mdls -name kMDItemLastUsedDate -raw " & quoted form of (POSIX path of theAlias)
if iso8601Text is "(null)" then return "Probably never opened"
set dt to (current date)
set savedDelimeters to AppleScript's text item delimiters
set AppleScript's text item delimiters to {"-", ":", space}
set {dt's year, dt's month, dt's day, dt's hours, dt's minutes, dt's seconds} to text items 1 thru 6 of iso8601Text
set AppleScript's text item delimiters to savedDelimeters
return dt
end Last_Opened_OF
I would like to know if it work correctly also on other computers (in a different locale). In general, I would like to have a universal solution with good speed. A good AsObjC solution to this problem would also come in handy.
NOTE: the result should be localized AppleScript date object (not the string)
It does so here in a German locale: date "Montag, 17. April 2023 um 09:57:55". Or rather: Kind of. The output of mdls is 2023-04-17 09:57:55 +0000. So, thatâs in GMT. But Iâm on GMT+0200, which the script does not consider. See here:
As usual, I donât know about AS(ObjC). Hereâs a version in JXA, I guess the AS variant looks similar (albeit a bit longer). The script foregoes the check if the attribute exists, though.
Here, the result is a JavaScript Date object, which console.log implicitly converts to a String: Mon Apr 17 2023 11:57:55 GMT+0200 (Mitteleuropäische Sommerzeit)
Which is, coincidentally, the correct time. So, maybe going the ASObjC way is better, not only speed-wise.
So, the NSURLContentAccessKey would be the same as the kMDItemLastOpenDate? Interestingly, not here. For my file, the NSURLContentAccessKey records NSURLContentAccessDateKey:date "Montag, 17. April 2023 um 11:58:10" , whereas the kMDItemLastOpenDate is 2023-04-17 11:57:55, so about 15 seconds earlier.
I know, nit-picking. But still â the open time is when the file was opened (eg by an application). The contentaccessdate being slightly later might mean that it refers to either the time when the app has read the content or when it has saved the content again.
Appleâs documentation, as usual, is preciously mum about the details.
dt is a date object obtained using current date. If the scriptâs run on the 31st of some month and you set dtâs month to February, April, June, September, or November, the rollover will be into the following month. Thatâs why you should set the day to < 29 before changing the month.
Yes it is not Last Opened Date. The correct AsObjC solution should read kMDItemLastUsedDate (like in your JsObjC code. The result is ISO8601 string. Then should exist additional step: converting ISO8601 string to NSDate, then to AppleScript date.
I just take a big doubt that you need to take into account the GMT - offset. After all, the last opening of the file is entered locally, that is, mdls should always reflect +0000, which it does. For new files and files downloaded somewhere (+ not opened yet), the result is the string â(null)â.
The correct test would not be what you think is correct, but whether the Last Opened file in the Finder window matches the result of my script. So far I have put a like to everyone - for participation.
Nope. The value returned from $.MDItemCopyAttribute is an NSDate (in that case). Which is converted to a JavaScript Date object by appending .js to the value.
In my script, This Date object is then implicitly converted to a String by passing it as a parameter to console.log().
I suppose that in the case of ASObjC, the value returned by MDCopyItemAttribute() would be an AppleScript date object/structure/record/whatever, not a string. In any case, the return value of MDCopyItemAttribute() is a CFTypeRef, not a CFString.
Right. It does. But my timezone is not +0000. Your script takes the output of mdls and doesnât consider the local timezone. So, the resulting date string is off by two hours (in my case). One can, of course, argue that the date should always be in UTC. But that might be a bit confusing, since Finder and other apps do consider the timezone when displaying the time.
Which means that you could end up with a âlast accessed timeâ that is before the âcreated timeâ shown in Finder. Leading to more confusion. Therefore, I suggest to
either use the MDItem approach with AS/JSObjC (which at least for JS does return the time in the local timezone)
or manually correct the timezone returned by mdls (which is the approach taken in the post I linked to before).
Itâs not âin terminalâ that you use a different timezone, itâs globally on your machine. If you run a date in terminal, youâll see the timezone your machine is currently in. In my case, itâs CEST, aka central european summer time. I guess yourâs is the same.
The timezone is set with the file /etc/localtime, and you can see it with
Thatâs a binary file, though! When you move to another TZ, your Mac automatically adjusts the value (unless youâve changed your global Time/Date preferences)
Thanks to everyone for participating in the discussion. Special thanks to @chrillek who helped me clear up some mishaps with the mdls result. For some reason, mdls does not take into account localization. That is, my original script also works inaccurately.
The JsObjC code provided by @chrillek is the solution, so Iâll accept it. The person is just an ace in JavaScript, but not familiar with AsObjC.
For those who prefer AsObjC, Iâve written here an AsObjC counterpart for the JsObjC code provided by @chrillek. It also works correctly and is the solution.
.
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
set posixPath to POSIX path of (choose file)
set theURL to (current application's |NSURL|)'s fileURLWithPath:posixPath
set mdItem to current application's NSMetadataItem's alloc()'s initWithURL:theURL
(mdItem's valueForAttribute:"kMDItemLastUsedDate") as date
Your script fails on my mac.
When i run script below, you will notice that âkMDItemLastUsedDateâ is not one of the keys available.
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
use framework "Foundation"
set posixPath to POSIX path of (choose file)
set theURL to (current application's |NSURL|)'s fileURLWithPath:posixPath
set mdItem to current application's NSMetadataItem's alloc()'s initWithURL:theURL
mdItem's attributes() as list
Iâm assuming it would be one of there (âkMDItemContentModificationDateâ or âkMDItemUserModifiedDateâ or âkMDItemFSContentChangeDateâ)
The first two return a date. The last one returns an array(list) with 1 date in it.
(They are all the same date/time)
use AppleScript version "2.5" -- EI Capitan (10.11) or later
use framework "Foundation"
use scripting additions
set posixPath to POSIX path of (choose file)
set theURL to (current application's |NSURL|)'s fileURLWithPath:posixPath
set mdItem to current application's NSMetadataItem's alloc()'s initWithURL:theURL
try
return (mdItem's valueForAttribute:"kMDItemLastUsedDate") as date
on error
return missing value -- not opened yet
end try
FWIW, I would use Fredrik71âs solution. It returns the exact same result as the NSMetadataItem ASObjC solution (to the second) on my Ventura computer, and it works with files on drives that are not indexed (important to me). My test files were Shaneâs ASObjC book, and a text file I created. I opened these files by double-clicking on them in Finder, and by opening them from within Preview/TextEdit.
My test implementation of Fredrik71âs suggestion:
use AppleScript version "2.5" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
set theFile to (choose file)
set theURL to current application's |NSURL|'s fileURLWithPath:(POSIX path of theFile)
set theKey to current application's NSURLContentAccessDateKey
set {theResult, theDate} to (theURL's getResourceValue:(reference) forKey:theKey |error|:(missing value))
return theDate as date
Well, the times are not always the same. But the ânot indexedâ argument is a strong one - kMDItemLastOpenDate might only be available for spotlighted files.
set theKey to current applicationâs NSURLContentAccessDateKey
just do this
use AppleScript version "2.5" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
set theFile to (choose file)
set theURL to current application's |NSURL|'s fileURLWithPath:(POSIX path of theFile)
set {theResult, theDate} to (theURL's getResourceValue:(reference) forKey:"NSURLContentAccessDateKey" |error|:(missing value))
return theDate as date