Swift 如何将日期信息传递给AppleScript?

Swift 如何将日期信息传递给AppleScript?,swift,applescript,nsapplescript,nsappleeventdescriptor,Swift,Applescript,Nsapplescript,Nsappleeventdescriptor,我正在制作一个可以通过NSAppleScript运行AppleScript的应用程序。 一切都很好,但我还没有弄清楚如何将日期信息从我的应用程序传递到AppleScript。(由于AppleScript具有日期类型,我认为这是可能的) 我将参数传递给AppleScript的方式是通过NSAppleEventDescriptor。我从谷歌了解到,我可以将其作为typeLongDateTime类型传递: - (id)initWithDate:(NSDate *)date { LongDat

我正在制作一个可以通过NSAppleScript运行AppleScript的应用程序。 一切都很好,但我还没有弄清楚如何将日期信息从我的应用程序传递到AppleScript。(由于AppleScript具有日期类型,我认为这是可能的) 我将参数传递给AppleScript的方式是通过NSAppleEventDescriptor。我从谷歌了解到,我可以将其作为typeLongDateTime类型传递:

- (id)initWithDate:(NSDate *)date {
     LongDateTime ldt;  
     UCConvertCFAbsoluteTimeToLongDateTime(CFDateGetAbsoluteTime((CFDateRef)date), &ldt);
     return [self initWithDescriptorType:typeLongDateTime
                                   bytes:&ldt
                                  length:sizeof(ldt)];
}
不幸的是,LongDateTime类型早就不存在了,因为我使用的是Swift和OSX10.10。甚至核心服务功能UCConvertCFAbsoluteTimeToLongDateTime也已从10.10.3中删除

现在我被卡住了


你有什么灵感吗?

似乎
LongDateTime
是一个有符号的64位整数,表示 日期
d
为格林尼治标准时间1904年1月1日以来的秒数,由时区偏移量调整 对于本地时区(包括夏令时)中的
d
如果DST在
d
处处于活动状态,则为偏移量

下面的代码给出了与我测试的所有日期(冬季和夏季)的Objective-C代码相同的结果


Swift 3的更新:

class DateEventDescriptor : NSAppleEventDescriptor {

    convenience init?(date: Date) {
        let secondsSince2001 = Int64(date.timeIntervalSinceReferenceDate)
        var secondsSince1904 = secondsSince2001 + 3061152000
        secondsSince1904 += Int64(NSTimeZone.local.secondsFromGMT(for: date))
        self.init(descriptorType: DescType(typeLongDateTime),
                  bytes: &secondsSince1904, length: MemoryLayout.size(ofValue: secondsSince1904))
    }
}
macOS 10.11的更新:

class DateEventDescriptor : NSAppleEventDescriptor {

    convenience init?(date: Date) {
        let secondsSince2001 = Int64(date.timeIntervalSinceReferenceDate)
        var secondsSince1904 = secondsSince2001 + 3061152000
        secondsSince1904 += Int64(NSTimeZone.local.secondsFromGMT(for: date))
        self.init(descriptorType: DescType(typeLongDateTime),
                  bytes: &secondsSince1904, length: MemoryLayout.size(ofValue: secondsSince1904))
    }
}
从macOS 10.11开始,有一个

 NSAppleEventDescriptor(date: Date)
初始化器,以便不再需要上述解决方法。
(感谢@Wevah提供这些信息。)

受Martin的启发,我知道LongDateTime类型只是记录1904-01-01午夜以来的时间间隔。AppleScript使用它来表示日期。然而,AppleScript中有一件奇怪的事情,就是日期类型没有时区概念。因此,简单地传递1904-01-01 00:00:00+0000之后的时间间隔,只会使AppleScript中的结果日期以GMT显示时间。这就是为什么我尝试了Martin的建议,但从AppleScript中显示了错误的时间。由于这是一个涉及时差的数据,我得到了以下适合我的方法:

convenience init?(date: NSDate) {
    struct StaticWrapper {
        static var longDateTimeReferenceDate: NSDate!
    }
    if StaticWrapper.longDateTimeReferenceDate == nil {
        let formatter = NSDateFormatter()
        let c = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
        formatter.calendar = c
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        StaticWrapper.longDateTimeReferenceDate = formatter.dateFromString("1904-01-01 00:00:00")
    }

    var secondsSince1904 = Int64(date.timeIntervalSinceDate(StaticWrapper.longDateTimeReferenceDate))
    self.init(descriptorType: DescType(typeLongDateTime), bytes: &secondsSince1904, length: sizeofValue(secondsSince1904))
}

日期格式化程序中没有提供时区信息,它隐式地包含当前时区。因此,生成的时间间隔将使AppleScript以本地时区显示时间。其行为类似于AppleScript命令“当前日期”。

有一个鲜为人知的CoreFoundation常量
KCFabSoluteTimeIntervalence1904
,表示1904年和2001年之间的差异。此NSDate扩展将NSDate转换为NSAppleEventDescriptor,反之亦然

extension NSDate {

  func appleScriptDate() -> NSAppleEventDescriptor
  {
    var secondsSince1904 = Int64(self.timeIntervalSinceReferenceDate + kCFAbsoluteTimeIntervalSince1904)
    return NSAppleEventDescriptor(descriptorType: DescType(typeLongDateTime), bytes: &secondsSince1904, length: sizeofValue(secondsSince1904))!
  }

  convenience init(appleScriptDate : NSAppleEventDescriptor)
  {
    var secondsSince1904 : Int64 = 0
    let data = appleScriptDate.data
    data.getBytes(&secondsSince1904, length: data.length)
    self.init(timeIntervalSinceReferenceDate:NSTimeInterval(secondsSince1904) - kCFAbsoluteTimeIntervalSince1904)
  }

}

如果需要调整时区信息(转换为AppleScript date不会保留时区),请在Swift中添加
NSTimeZone.systemTimeZone().secondsFromGMT
,或在AppleScript中添加
time to GMT
,我更新了vadian的Swift 3扩展名:

extension NSDate {

    func appleScriptDate() -> NSAppleEventDescriptor
    {
        var secondsSince1904 = Int64(self.timeIntervalSinceReferenceDate + kCFAbsoluteTimeIntervalSince1904)
        return NSAppleEventDescriptor(descriptorType: DescType(typeLongDateTime), bytes: &secondsSince1904, length: MemoryLayout.size(ofValue: secondsSince1904))!
    }

    convenience init(appleScriptDate : NSAppleEventDescriptor)
    {
        var secondsSince1904 : Int64 = 0
        withUnsafeMutablePointer(to: &secondsSince1904) {
            _ = appleScriptDate.data.copyBytes(
                to: UnsafeMutableBufferPointer(start: $0, count: 4),
                from: 0..<4)
        }
        self.init(timeIntervalSinceReferenceDate:TimeInterval(secondsSince1904) - kCFAbsoluteTimeIntervalSince1904)
    }
}
扩展日期{
func appleScriptDate()->NSAppleEventDescriptor
{
var secondsSince1904=Int64(self.timeintervalncereferencedate+kcfabsolutetimeintervalnce1904)
返回NSAppleEventDescriptor(描述符类型:DescType(typeLongDateTime),字节:&secondsSince1904,长度:MemoryLayout.size(of值:secondsSince1904))!
}
便利初始化(appleScriptDate:NSAppleEventDescriptor)
{
var secondsSince1904:Int64=0
WithUnsafemutable指针(指向:&secondsSince1904){
_=appleScriptDate.data.copyBytes(
to:UnsafemeutableBufferPointer(开始:$0,计数:4),

from:0.谢谢你,Martin。你的建议很有效。但是,它似乎有一个小问题:1904年和2001年之间的秒差应该是3061180800(而不是3061152000),请确认一下好吗?我很确定3061152000是正确的。试试
让date=NSDate(timeintervalencereferencedate:-3061152000);println(date)
Output:
1904-01-01 00:00:00+0000
。马丁,我认为你在这一点上是对的。但我认为这是错误的原因是,当我以3061152000的方式传递longDateTime时,AppleScript中的日期值不正确。我怀疑这可能与时区有关。我还没有完全弄清楚。@Terry:是的,可能是时区问题。但是我不知道如何在没有任何进一步信息的情况下帮助您解决这个问题。请注意,
println(date)
总是以GMT打印时间。太好了,谢谢。我将留下我的答案供进一步参考。:)