3

我正在制作一个可以通过 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 并且在 OS X 10.10 下。甚至核心服务功能 UCConvertCFAbsoluteTimeToLongDateTime 也已从 10.10.3 中删除。

现在我被困住了。

你有什么启发灵感的想法吗?

4

4 回答 4

2

这似乎LongDateTime是一个有符号的 64 位整数,它表示日期d为自 1904 年 1 月 1 日格林威治标准时间以来的秒数,由d本地时区的时区偏移量进行调整(如果 DST 是,则包括夏令时时间偏移量活跃于d)。

对于我测试的所有日期(冬季时间和夏季时间),以下代码给出的结果与您的 Objective-C 代码相同。

class DateEventDescriptor : NSAppleEventDescriptor {

    convenience init?(date : NSDate) {
        let secondsSince2001 = Int64(date.timeIntervalSinceReferenceDate)
        var secondsSince1904 = secondsSince2001 + 3061152000
        secondsSince1904 += Int64(NSTimeZone.localTimeZone().secondsFromGMTForDate(date))
        self.init(descriptorType: DescType(typeLongDateTime),
            bytes: &secondsSince1904, length: sizeofValue(secondsSince1904))
    }
}

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 更新:

从 macOS 10.11 开始,有一个

 NSAppleEventDescriptor(date: Date)

初始化程序,因此不再需要上述解决方法。(感谢@Wevah 提供此信息。)

于 2015-06-02T08:39:50.947 回答
1

受 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 命令“当前日期”。

于 2015-06-03T05:20:14.910 回答
1

有一个鲜为人知的 CoreFoundation 常量kCFAbsoluteTimeIntervalSince1904代表 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 日期不保留时区)NSTimeZone.systemTimeZone().secondsFromGMT在 Swift 或time to GMTAppleScript 中添加

于 2015-06-24T10:13:53.893 回答
0

我为 Swift 3 更新了 vadian 的扩展:

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)
    }
}
于 2016-10-07T09:31:02.417 回答