在Swift中,如何从dispatch_time_t获取NSDate?

Le *_*ced 5 nsdate grand-central-dispatch ios swift

"Walltime"是Grand Central Dispatch使用的一种鲜为人知的时间格式.Apple在这里谈到它:

https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/

但是有一些东西真的很方便,但它是一个粘性的检票口.很难让它与其他时间格式一起玩得很好,这就是我的问题所在.

我可以通过将a NSDate转换为a 来进行壁挂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)
Run Code Online (Sandbox Code Playgroud)

但是主爱一只鸭子,我无法弄清楚如何让它重新变成一只鸭子NSDate.这是我的尝试:

public func toNSDate(wallTime: dispatch_time_t)->NSDate {
    let wallTimeAsSeconds = Double(wallTime) / Double(NSEC_PER_SEC)
    let date = NSDate(timeIntervalSince1970: wallTimeAsSeconds)
    return date
}
Run Code Online (Sandbox Code Playgroud)

结果NSDate不只是关闭,而是有点滑稽,如五百年或其他什么.正如Martin R所指出的那样,问题在于它dispatch_time_t是一个不透明的值,没有时间表示.

有谁知道如何做到这一点?

编辑:如果创建壁挂时间的过程令人困惑,这基本上是正在发生的事情:

NSDate使用a定义时间,Double小数点后的所有内容都是纳秒.dispatch_time,可以创建一个walltime,定义时间UInt64,所以你必须在它之间进行转换DoubleUInt64使用它.要进行这种转换,您需要使用a timespec,它需要秒和纳秒作为单独的参数,每个参数必须是Int.

一个完整的转换'继续!

Mar*_*n R 12

真正的答案是:你做不到.

"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;
Run Code Online (Sandbox Code Playgroud)

因此,dispatch_time_t使用未记录的"抽象"时间表示,甚至可能在发布之间进行更改.

话虽这么说,让我们有一些乐趣,并试图找出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;
}
Run Code Online (Sandbox Code Playgroud)

有趣的部分是最后一行:它取纳秒的负值,并将此值转换回(无符号)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
}
Run Code Online (Sandbox Code Playgroud)

事实上,这会将walltime正确地转换回原始版本 NSDate,至少在我在OS X应用程序中测试它时.

但是再说一遍:不要这样做!您将依赖于未记录的表示形式,该表示形式可能会在OS版本之间发生变化 可能还存在上述代码中未考虑的特殊情况.iOS运行时中的表示也可能不同,我没试过. 你被警告了!