Convert a Date (absolute time) to be sent/received across the network as Data in Swift?

醉酒当歌 提交于 2019-11-28 06:20:49

问题


I am looking for a Swifty way to generate a timestamp.

My macOS app logs some data and stamps it with the time the data was created. The data will then be sent across the network (as Data) to be reconstructed on an iPad.

Is there any Swift class that will work to generate the timestamp? NSDate? NSTimeIntervalSince1970? CFAbsoluteTimeGetCurrent()

The requirements are:

  1. Store the timestamp in as few bytes as possible (pref. Int)
  2. Have some semblance to real Earth time (I'd rather not generate my own time format)
  3. Millisecond accuracy
  4. Fast to construct
  5. iOS 9+, macOS 10.10+

回答1:


You can send your Date converting it to Data (8-bytes floating point) and back to Date as follow:

extension Numeric {
    var data: Data {
        var source = self
        return .init(bytes: &source, count: MemoryLayout<Self>.size)
    }
    init<D: DataProtocol>(_ data: D) {
        var value: Self = .zero
        let size = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0)} )
        assert(size == MemoryLayout.size(ofValue: value))
        self = value
    }
}

extension UInt64 {
    var bitPattern: Double { .init(bitPattern: self) }
}

extension Date {
    var data: Data { timeIntervalSinceReferenceDate.bitPattern.littleEndian.data }
    init<D: DataProtocol>(data: D) {
        self.init(timeIntervalSinceReferenceDate: data.timeIntervalSinceReferenceDate)
    }
}

extension DataProtocol {
    func value<N: Numeric>() -> N { .init(self) }
    var uint64: UInt64 { value() }
    var timeIntervalSinceReferenceDate: TimeInterval { uint64.littleEndian.bitPattern }
    var date: Date { .init(data: self) }
}

Playground Testing

let date = Date()            // "Nov 15, 2019 at 12:13 PM"
let data = date.data         // 8 bytes
print(Array(data))           // "[25, 232, 158, 22, 124, 191, 193, 65]\n"
let loadedDate = data.date   // "Nov 15, 2019 at 12:13 PM"
print(date == loadedDate)    // "true\n"



回答2:


Here is how I used Leo Dabus's answer.

public struct Timestamp: Equatable, Comparable {

    public let date: Date

    public init() {
        self.date = Date()
    }

    public func toData() -> Data {
        var date = self.date
        return Data(bytes: &date, count: MemoryLayout<Date>.size)
    }

    public init(fromData data: Data) {
        guard data.count == 8 else {
            fatalError("Insufficient bytes. expected 8; got \(data.count). data: \(data)")
        }
        self.date = data.withUnsafeBytes { $0.pointee }
    }

    public static func ==(lhs: Timestamp, rhs: Timestamp) -> Bool {
        return lhs.date == rhs.date
    }

    public static func <(lhs: Timestamp, rhs: Timestamp) -> Bool {
        return lhs.date < rhs.date
    }
}



回答3:


Use TimeIntervalSince1970 type:

let exactTimeInMilliseconds = Date().timeIntervalSince1970

Original answer was very inefficient.



来源:https://stackoverflow.com/questions/47502591/convert-a-date-absolute-time-to-be-sent-received-across-the-network-as-data-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!