SwiftAutomation icon indicating copy to clipboard operation
SwiftAutomation copied to clipboard

typeLongDateTime suggested fix

Open ronzo99 opened this issue 4 years ago • 4 comments

A couple of tweaks to handle AppleScript typeLongDateTime:

  1. unpackAsDate calls unpackAsInteger, which does not handle typeLongDateTime. Add to unpackAsInteger:
    case typeLongDateTime:
        result = T(exactly: Int64(bigEndian: try decodeFixedWidthValue(descriptor.data)))

or alternatively modify existing case:

    case typeSInt64, typeLongDateTime:
        result = T(exactly: Int64(bigEndian: try decodeFixedWidthValue(descriptor.data)))
  1. now that unpackAsDate has computed the TimeInterval delta, fix a bug in the return statement, changing + to -:

    return Date(timeIntervalSinceReferenceDate: delta - epochDelta)

  2. test with a folder on the desktop:

let finder = Finder()
print(try finder.folders["TEMP"].creationDate.get())
  1. perhaps a better name for "delta" might be "secondsSince1904"?

ronzo99 avatar Jun 16 '21 14:06 ronzo99

@ronzo99 @hhas Just stumbled upon this bug, looking for a solution and found your old issue. Thank you for posting! I'd like to add to that that I've noticed yet another bug, related to time zones.

As odd as it may seem, it seems to me that AppleScript returns a timestamp relative to the user's (or processes?) time zone and not in UTC. It feels quite wrong to do the following but maybe this is just a flaw in AppleScript/AppleEvents itself? So what I did is change the return statement to:

return Date(timeIntervalSinceReferenceDate: delta - epochDelta - TimeInterval(TimeZone.current.secondsFromGMT()))

to account for the time zone offset already included in delta.

Isn't it possible for a macOS process to have a different time zone set than the system? If so, this code is going to break and I would have no idea how to convert it back to UTC.

Edit: Just looked up the private implementation of -[NSAppleEventDescriptor dateValue] in Foundation and it converts the timestamp from the descriptor, calling UCConvertLongDateTimeToCFAbsoluteTime which, implemented in CarbonCore uses CFTimeZoneGetSecondsFromGMT(CFTimeZoneCopyDefault() …) and then creates the date object from the resulting timestamp via +[NSDate dateWithTimeIntervalSinceReferenceDate:] 😅. So turns out this is in fact the correct approach!

tobi-mb avatar Jun 16 '23 23:06 tobi-mb

Great sleuthing! I wonder if @hhas has abandoned this project now, like so many others? Either way, I’ve found his source code very instructive for coding my own AppleScript support.

ronzo99 avatar Jun 17 '23 16:06 ronzo99

@ronzo99 Could you elaborate on why SwiftAutomation didn't meet your requirements and what your own code does better now? I'm considering using it for production code at the moment.

tobi-mb avatar Jun 17 '23 19:06 tobi-mb

@tobi-mb I was looking at it when I was thinking of converting some ObjC + ScriptingBridge automation code to Swift. I found Swift Automation worked as expected, but eventually decided not to rewrite my code in Swift. Good luck with your project!

ronzo99 avatar Jun 17 '23 20:06 ronzo99