在 Swift 中,如何从 dispatch_time_t 中获取 NSDate?
In Swift, how can I get an NSDate from a dispatch_time_t?
"Walltime" 是 Grand Central Dispatch 使用的一种鲜为人知的时间格式。苹果在这里谈论它:
https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/
虽然有些东西确实很方便,但它是一个粘性检票口。很难让它与其他时间格式兼容,这就是我的问题。
我可以通过将 NSDate
变成 timespec
,然后与 dispatch_walltime
:
一起使用来制作 walltime
let now = NSDate().timeIntervalSince1970
let nowWholeSecsFloor = floor(now)
let nowNanosOnly = now - nowWholeSecsFloor
let nowNanosFloor = floor(nowNanosOnly * Double(NSEC_PER_SEC))
var thisStruct = timespec(tv_sec: Int(nowWholeSecsFloor),
tv_nsec: Int(nowNanosFloor))
let wallTime = dispatch_walltime(& thisStruct, 0)
但是天哪,我不知道如何把它变回 NSDate
。这是我的尝试:
public func toNSDate(wallTime: dispatch_time_t)->NSDate {
let wallTimeAsSeconds = Double(wallTime) / Double(NSEC_PER_SEC)
let date = NSDate(timeIntervalSince1970: wallTimeAsSeconds)
return date
}
由此产生的 NSDate
不仅偏离了,而且有点滑稽地偏离了,比如五百年之类的。正如 Martin R 指出的那样,问题在于 dispatch_time_t
是一个不透明的值,具有未记录的时间表示形式。
有人知道怎么做吗?
编辑:如果创建 walltime 的过程令人困惑,这基本上就是正在发生的事情:
NSDate
用Double
定义时间,小数点后的都是纳秒。 dispatch_time
,可以创建一个walltime,用UInt64
定义时间,所以你必须在Double
和UInt64
之间转换才能使用它。要进行该转换,您需要使用 timespec
,它将秒和纳秒作为单独的参数,每个参数都必须是 Int
.
大量转换正在进行中!
真正的答案是:你不能。
在 "time.h" 头文件中指出:
/*!
* @typedef dispatch_time_t
*
* @abstract
* A somewhat abstract representation of time; where zero means "now" and
* DISPATCH_TIME_FOREVER means "infinity" and every value in between is an
* opaque encoding.
*/
typedef uint64_t dispatch_time_t;
所以 dispatch_time_t
使用了一种未记录的 "abstract" 时间表示,它
甚至可能会在不同版本之间发生变化。
话虽这么说,让我们找点乐子,试着弄清楚是什么
a dispatch_time_t
确实是。所以我们看一下 "time.c",它包含了
dispatch_walltime()
:
dispatch_time_t
dispatch_walltime(const struct timespec *inval, int64_t delta)
{
int64_t nsec;
if (inval) {
nsec = inval->tv_sec * 1000000000ll + inval->tv_nsec;
} else {
nsec = (int64_t)_dispatch_get_nanoseconds();
}
nsec += delta;
if (nsec <= 1) {
// -1 is special == DISPATCH_TIME_FOREVER == forever
return delta >= 0 ? DISPATCH_TIME_FOREVER : (dispatch_time_t)-2ll;
}
return (dispatch_time_t)-nsec;
}
有趣的部分是最后一行:它取 negative 值
纳秒,并且此值被转换回(无符号)dispatch_time_t
。还有一些特殊情况。
因此,要反转转换,我们必须否定
dispatch_time_t
并将其视为纳秒:
public func toNSDate(wallTime: dispatch_time_t)->NSDate {
// Tricky part HERE:
let nanoSeconds = -Int64(bitPattern: wallTime)
// Remaining part as in your question:
let wallTimeAsSeconds = Double(nanoSeconds) / Double(NSEC_PER_SEC)
let date = NSDate(timeIntervalSince1970: wallTimeAsSeconds)
return date
}
确实,这会将挂钟时间正确地转换回原来的时间
NSDate
,至少当我在 OS X 应用程序中测试它时是这样。
但是再说一次:不要这样做! 你会依赖一个未记录的表示,它可以在 OS 版本之间改变。还有可能
是上述代码中未考虑的特殊情况。
iOS 运行时中的表示也可能不同,我做到了
不要那样做。
您已收到警告!
"Walltime" 是 Grand Central Dispatch 使用的一种鲜为人知的时间格式。苹果在这里谈论它:
https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/
虽然有些东西确实很方便,但它是一个粘性检票口。很难让它与其他时间格式兼容,这就是我的问题。
我可以通过将 NSDate
变成 timespec
,然后与 dispatch_walltime
:
let now = NSDate().timeIntervalSince1970
let nowWholeSecsFloor = floor(now)
let nowNanosOnly = now - nowWholeSecsFloor
let nowNanosFloor = floor(nowNanosOnly * Double(NSEC_PER_SEC))
var thisStruct = timespec(tv_sec: Int(nowWholeSecsFloor),
tv_nsec: Int(nowNanosFloor))
let wallTime = dispatch_walltime(& thisStruct, 0)
但是天哪,我不知道如何把它变回 NSDate
。这是我的尝试:
public func toNSDate(wallTime: dispatch_time_t)->NSDate {
let wallTimeAsSeconds = Double(wallTime) / Double(NSEC_PER_SEC)
let date = NSDate(timeIntervalSince1970: wallTimeAsSeconds)
return date
}
由此产生的 NSDate
不仅偏离了,而且有点滑稽地偏离了,比如五百年之类的。正如 Martin R 指出的那样,问题在于 dispatch_time_t
是一个不透明的值,具有未记录的时间表示形式。
有人知道怎么做吗?
编辑:如果创建 walltime 的过程令人困惑,这基本上就是正在发生的事情:
NSDate
用Double
定义时间,小数点后的都是纳秒。 dispatch_time
,可以创建一个walltime,用UInt64
定义时间,所以你必须在Double
和UInt64
之间转换才能使用它。要进行该转换,您需要使用 timespec
,它将秒和纳秒作为单独的参数,每个参数都必须是 Int
.
大量转换正在进行中!
真正的答案是:你不能。
在 "time.h" 头文件中指出:
/*!
* @typedef dispatch_time_t
*
* @abstract
* A somewhat abstract representation of time; where zero means "now" and
* DISPATCH_TIME_FOREVER means "infinity" and every value in between is an
* opaque encoding.
*/
typedef uint64_t dispatch_time_t;
所以 dispatch_time_t
使用了一种未记录的 "abstract" 时间表示,它
甚至可能会在不同版本之间发生变化。
话虽这么说,让我们找点乐子,试着弄清楚是什么
a dispatch_time_t
确实是。所以我们看一下 "time.c",它包含了
dispatch_walltime()
:
dispatch_time_t
dispatch_walltime(const struct timespec *inval, int64_t delta)
{
int64_t nsec;
if (inval) {
nsec = inval->tv_sec * 1000000000ll + inval->tv_nsec;
} else {
nsec = (int64_t)_dispatch_get_nanoseconds();
}
nsec += delta;
if (nsec <= 1) {
// -1 is special == DISPATCH_TIME_FOREVER == forever
return delta >= 0 ? DISPATCH_TIME_FOREVER : (dispatch_time_t)-2ll;
}
return (dispatch_time_t)-nsec;
}
有趣的部分是最后一行:它取 negative 值
纳秒,并且此值被转换回(无符号)dispatch_time_t
。还有一些特殊情况。
因此,要反转转换,我们必须否定
dispatch_time_t
并将其视为纳秒:
public func toNSDate(wallTime: dispatch_time_t)->NSDate {
// Tricky part HERE:
let nanoSeconds = -Int64(bitPattern: wallTime)
// Remaining part as in your question:
let wallTimeAsSeconds = Double(nanoSeconds) / Double(NSEC_PER_SEC)
let date = NSDate(timeIntervalSince1970: wallTimeAsSeconds)
return date
}
确实,这会将挂钟时间正确地转换回原来的时间
NSDate
,至少当我在 OS X 应用程序中测试它时是这样。
但是再说一次:不要这样做! 你会依赖一个未记录的表示,它可以在 OS 版本之间改变。还有可能 是上述代码中未考虑的特殊情况。 iOS 运行时中的表示也可能不同,我做到了 不要那样做。 您已收到警告!