Search code examples
swiftdatecomparison

Dates are not equal while using timeIntervalSince1970


I've just run the code below several times and see that sometimes date1 and date2 are equal but sometimes are not.

    let date1 = Date()
    let date2 = Date(timeIntervalSince1970: date1.timeIntervalSince1970)

    print(date1)
    print(date2)
    print(date1.timeIntervalSince1970)
    print(date2.timeIntervalSince1970)
    print(date1 == date2)

So sometimes I get:

2019-03-22 05:52:30 +0000
2019-03-22 05:52:30 +0000

1553233950.498001
1553233950.498001

false

These dates look the same but comparison tells me they are different. The problem is that the date2 is slightly different from the date1. To prove it I can write:

print(date1.timeIntervalSince(date2))

and get:

-1.1920928955078125e-07

So it there any way to translate date1 to number and then back to date2 which is equal to date1?


Solution

  • The problem is the usage of timeIntervalSince1970. If you use this, the Date implementation will do some Double calculations to align it to the reference date (2001-01-01).

    If you use timeIntervalSinceReferenceDate instead, this will be used directly, and your code should work then:

    for i in 1...200000 {
        let date1 = Date()
        let date2 = Date(timeIntervalSinceReferenceDate: date1.timeIntervalSinceReferenceDate)
        if (date1 != date2) {
            // never called on my machine:
            let delta = date1.timeIntervalSince(date2)
            print("\(i): \(delta)")
        }
    }
    

    For your information, here the interesting parts of struct Date implementation on https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/Date.swift - you see the calculation done in the first init:

    public struct Date : ReferenceConvertible, Comparable, Equatable {
    
        fileprivate var _time: TimeInterval
        public static let timeIntervalBetween1970AndReferenceDate: TimeInterval = 978307200.0
    
        public init(timeIntervalSince1970: TimeInterval) {
            self.init(timeIntervalSinceReferenceDate: timeIntervalSince1970 - Date.timeIntervalBetween1970AndReferenceDate)
        }
        public init(timeIntervalSinceReferenceDate ti: TimeInterval) {
            _time = ti
        }
    }