Eric
Eric

Reputation: 769

How to convert `Date` to `Data`, and vice versa in Swift 5?

I'm trying to save a date in Keychain, and (from my understanding) this first requires converting the Date object into a Data object.

This Stack Overflow Q/A explains how to do it (or at least part of it) in Swift 3, but I'm hoping someone can provide the to/from functions in Swift 5 (since at least one of the methods in that solution are deprecated and I'm worried something else hasn't stood the test of time either).

Upvotes: 1

Views: 1454

Answers (2)

Larme
Larme

Reputation: 26086

A Date is a juste a Timestamp (number of seconds since reference date of 1970 at UTC) as an object with fancy methods and other utilities. That's nothing more.

So based on the answer Double to Data (and reverse):

Input

let date = Date()
print(date)

Date -> Timestamp -> Data

let timestamp = date.timeIntervalSinceReferenceDate
print(timestamp)
let data = withUnsafeBytes(of: timestamp) { Data($0) }
print("\(data) - \(data.map{ String(format: "%02hhx", $0) }.joined())")

Data -> Timestamp -> Date

let retrievedTimestamp = data.withUnsafeBytes { $0.load(as: Double.self) }
print(retrievedTimestamp)
let retrievedDate = Date(timeIntervalSinceReferenceDate: retrievedTimestamp)
print(retrievedDate)

Output:

$>2021-09-13 08:17:50 +0000
$>1631521070.6852288
$>8 bytes - cadaab4bc24fd841
$>1631521070.6852288
$>2021-09-13 08:17:50 +0000

Upvotes: 9

Bradley Mackey
Bradley Mackey

Reputation: 7688

A "safer" (but less efficient) way to do this would be to use an Encoder/Decoder type, such as Foundations JSONEncoder/JSONDecoder. If the data gets corrupted in some way, these types will throw an Error, rather than trapping. You just need to ensure that the date encoding/decoding strategy is the same for each.

let myDate = Date()

let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .secondsSince1970
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .secondsSince1970

// TODO: handle errors correctly
let dateData = try! encoder.encode(myDate)
let retrievedDate = try! decoder.decode(Date.self, from: dateData)

assert(myDate == retrievedDate)

Upvotes: 6

Related Questions