我正在创建一个可以通过NSAppleScript运行AppleScript的应用程序。 一切都很好,但我无法弄清楚如何将日期信息从我的应用程序传递到AppleScript。 (由于AppleScript有日期类型,我想这是可能的) 我将参数传递给AppleScript的方法是通过NSAppleEventDescriptor。我从Google那里了解到我可以将其作为typeLongDateTime类型传递:
- (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中删除。
现在我被卡住了。
你有什么想法可以激发灵感吗?
答案 0 :(得分:2)
似乎LongDateTime
是一个带符号的64位整数,代表
日期d
,作为自1904年1月1日GMT以来的秒数,由时区偏移量调整
当地时区的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提供此信息。)
答案 1 :(得分: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命令“当前日期”。
答案 2 :(得分: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日期不保留时区),请在Swift中添加NSTimeZone.systemTimeZone().secondsFromGMT
或在AppleScript中添加time to GMT
答案 3 :(得分:0)
我更新了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)
}
}