问题
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:
- Store the timestamp in as few bytes as possible (pref.
Int) - Have some semblance to real Earth time (I'd rather not generate my own time format)
- Millisecond accuracy
- Fast to construct
- 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