2015-06-02 1 views
2

Я делаю одно приложение, которое может запускать AppleScript через NSAppleScript. Все было хорошо, но я не смог понять, как передавать информацию о дате из моего приложения в AppleScript. (Поскольку AppleScript имеет тип даты, я предполагаю, что это возможно) Способ передачи параметров AppleScript осуществляется через NSAppleEventDescriptor. Я узнал от Google, что я мог бы передать его в качестве typeLongDateTime типа:Как передать информацию о дате в AppleScript?

- (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.

Теперь я застрял.

Есть ли у вас идеи, которые вдохновляют?

ответ

2

Является ли кажется, что LongDateTime является подписано 64-битовое целое число, которое представляет дату d как число секунд, прошедших с 1 января 1904 года, по Гринвичу, с поправкой на смещение часового пояса для 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 за эту информацию.)

+0

Спасибо, Мартин. Ваше предложение работает. Однако, похоже, один сбой: разница секунд между 1904 и 2001 годами должна быть 3061180800 (а не 3061152000), пожалуйста, подтвердите? – Terry

+0

Я уверен, что 3061152000 верен. Попробуйте 'let date = NSDate (timeIntervalSinceReferenceDate: -3061152000); println (date) 'Выход:' 1904-01-01 00:00:00 + 0000'. –

+0

Мартин, я думаю, ты прав. Но причина, по которой я думал, что это неправильно, - это то, что я получил неправильное значение даты в AppleScript при прохождении longDateTime в пути 3061152000. Я подозреваю, что это может иметь какое-то отношение к часовому поясу. Я еще не понял это полностью. – Terry

1

Вдохновленный Мартином, я узнал, что тип LongDateTime - это всего лишь то, что записывает временной интервал с даты 1904-01-01 в полночь. И AppleScript использует его для представления дат. Однако в AppleScript одна странная вещь заключается в том, что для типа даты нет концепции часового пояса. Таким образом, просто передача временного интервала с 1904-01-01 00:00:00 +0000 приведет только к тому, что приведенная дата в AppleScript покажет время в GMT. Вот почему я попробовал предложение Мартина, но неправильно показал, что 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 «текущая дата».

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 GMT в AppleScript

+0

Приятно познакомиться с этим, спасибо, вадиан! – Terry

0

Я обновил расширение вадиан для 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) 
    } 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^