3

NSAppleScript 経由で AppleScript を実行できるアプリを 1 つ作成しています。すべてうまくいきましたが、アプリから AppleScript に日付情報を渡す方法がわかりませんでした。(AppleScript には日付型があるので、これは可能だと思います) AppleScript にパラメーターを渡す方法は、NSAppleEventDescriptor を使用します。typeLongDateTime 型として渡すことができることを Google から学びました。

- (id)initWithDate:(NSDate *)date {
     LongDateTime ldt;  
     UCConvertCFAbsoluteTimeToLongDateTime(CFDateGetAbsoluteTime((CFDateRef)date), &ldt);
     return [self initWithDescriptorType:typeLongDateTime
                                   bytes:&ldt
                                  length:sizeof(ldt)];
}

残念ながら、LongDateTime 型は、OS X 10.10 で Swift を使用しているため、長い間使用されていませんでした。コア サービス関数の UCConvertCFAbsoluteTimeToLongDateTime でさえ、10.10.3 から既に削除されています。

今、私は立ち往生しています。

インスピレーションを与えるアイデアはありますか?

4

4 に答える 4

2

これは、1904 年 1 月 1 日 GMT からの秒数としてLongDateTime日付を表す符号付き 64 ビット整数であり、ローカル タイム ゾーンのタイム ゾーン オフセット (DST の場合はサマータイム オフセットを含む) によって調整されているようです。でアクティブ)。ddd

次のコードは、テストしたすべての日付 (冬時間と夏時間) について、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

Inspired by Martin, I got to know that the LongDateTime type is just something that records time interval since the date 1904-01-01 midnight. And AppleScript utilizes it to represent dates. However, one weird thing in AppleScript is that there is no time zone concept for date type. So, simply passing the time interval since 1904-01-01 00:00:00 +0000, would only make the resulted date in AppleScript show the time in GMT. That was why I tried Martin's suggestion but got wrong time shown from the AppleScript. Since it is a data involving time difference, I got the following way works for me:

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))
}

The time zone information is not given in the date formatter, which implicitly includes the current time zone. Therefore, the resulted time interval will make the AppleScript to show the time in local time zone. Which behaves like the AppleScript command "current date".

于 2015-06-03T05:20:14.910 に答える
1

kCFAbsoluteTimeIntervalSince19041904 と 2001 の違いを表す、あまり知られていない CoreFoundation 定数があります。この 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 に答える