Как передать информацию о дате в AppleScript?
Я делаю одно приложение, которое может запускать AppleScript через NSAppleScript. Все было хорошо, но я не смог выяснить, как передать информацию о дате из моего приложения в AppleScript. (Так как AppleScript имеет тип даты, я полагаю, это возможно) Способ передачи параметров в AppleScript через NSAppleEventDescriptor. Я узнал от Google, что могу передать его как typeLongDateTime type:
- (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 ответа
Кажется, что LongDateTime
64-разрядное целое число со знаком, представляющее дату d
как количество секунд с 1 января 1904 года по Гринвичу, скорректированное на смещение часового пояса для d
в местном часовом поясе (включая смещение летнего времени, если летнее время активно в 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 за эту информацию.)
Вдохновленный Мартином, я узнал, что тип 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 "текущая дата".
Существует малоизвестная константа 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
в Свифте или time to GMT
в AppleScript
Я обновил расширение 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)
}
}