如何将日期信息传递给 AppleScript?
How to pass date information to AppleScript?
我正在制作一款可以通过 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 类型早已消失,因为我使用的是 Swift 并且在 OS X 10.10 下。甚至核心服务功能 UCConvertCFAbsoluteTimeToLongDateTime 也已从 10.10.3 中删除。
现在我卡住了。
您有什么启发灵感的想法吗?
似乎 LongDateTime
是一个带符号的 64 位整数,它表示
日期 d
自格林威治标准时间 1904 年 1 月 1 日以来的秒数,由时区偏移量调整
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))
}
}
Swift3 的更新:
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 提供此信息。)
受 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 命令 "current date".
有一个鲜为人知的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
或在AppleScripttime to GMT
中添加
我为 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: [=10=], count: 4),
from: 0..<4)
}
self.init(timeIntervalSinceReferenceDate:TimeInterval(secondsSince1904) - kCFAbsoluteTimeIntervalSince1904)
}
}
我正在制作一款可以通过 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 类型早已消失,因为我使用的是 Swift 并且在 OS X 10.10 下。甚至核心服务功能 UCConvertCFAbsoluteTimeToLongDateTime 也已从 10.10.3 中删除。
现在我卡住了。
您有什么启发灵感的想法吗?
似乎 LongDateTime
是一个带符号的 64 位整数,它表示
日期 d
自格林威治标准时间 1904 年 1 月 1 日以来的秒数,由时区偏移量调整
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))
}
}
Swift3 的更新:
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 提供此信息。)
受 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 命令 "current date".
有一个鲜为人知的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
或在AppleScripttime to GMT
中添加
我为 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: [=10=], count: 4),
from: 0..<4)
}
self.init(timeIntervalSinceReferenceDate:TimeInterval(secondsSince1904) - kCFAbsoluteTimeIntervalSince1904)
}
}