Do you need help on a specific subject? Use the contact form (Request a blog entry) on the right hand side.


NSDate, NSTimeInterval, UNIX time and Java Date | Timestamps in OS-X

Back in 1970 things were simple; hardly any computers around...
Then time started... computers arrived.
Computers, being what they are, need time...
And so the troubles started.

First there was UNIX Time. It was measured in seconds, and started in the year zero: 1 Jan 1970.
Since you can store a lot in 32 bit, and since memory was expensive, there was a consensus that 32 would be more than enough to store all the seconds you need.
Turns out, they were wrong.

So here we are today, with a baffling array of solutions. Since this blog is about Swift, its about MacOS (Unix) and iOS. Even so, we still need to interact with the world at large, so the most common time formats are still of interest.

The following are the most common:

NSDate: An internal representation of a moment in time, used in MacOS, iOS, tvOS and watchOS.

NSTimeInterval: A double value that is used to express the time elapsed between two moments in time. Commonly used to store the time between 1 Jan 1970 and another moment. It thus can be confused with Unix Time and Java Date.

Unix Time: Started out as a 32 unsigned integer that represents the number of seconds since 1 Jan 1970. Today all modern Unixes use a 64 bit unsigned integer. Due to the large size, it can safely be used (converted into) a singed integer 64 for just about all cases. This will fail sometime in the future, but I have not even bothered to calculate how far in the the future that is (probably after the sun stops shining...).

Java Date: This too measures the time since 1 Jan 1970, but counts in milli-seconds. It is thus 1000 x as large as the Unix Time. Still, it can be safely encapsulated in a signed 64 bit integer for most practical purposes.

Personally, I find it a bit disappointing that NSTimeInterval uses a double. I would have preferred an integer, 64 bit of course. While I can understand why Apple has done this it also makes comparing on equality difficult. (Remember: never compare a double (or float) on equality!). And though modern processors will do a pretty quick job on double compare, an integer compare is often faster.

If we have to exchange time information between applications and computers, the question is which representation do we use?

Simply defaulting to the standard of the system at hand can easily be the wrong answer. I would suggest to make a conscious choice. That could save a lot of hassle later on. (It's usually not a good day when you find out that you have to refactor all of your code -and tests- because you need to interface with another party that uses a different system...). Having said this, the safest choice is IMO the Java Date. It won't always be the right choice, but if offers a resolution that is high enough in most cases (when you need nano-second resolution, do a google on "timespec") and can be represented in a 64 bit integer.

In Swift it makes sense to create an extension for this. And while we are at it, we can include the conversions for the Unix time as well:

extension NSDate {

    /// Milli seconds since 1 Jan 1970
    var javaDate: Int64 {
        return Int64(self.timeIntervalSince1970 * 1000)
    /// Seconds since 1 Jan 1970
    var unixTime: Int64 {
        return Int64(self.timeIntervalSince1970)
    /// From milli seconds since 1 Jan 1970
    static func fromJavaDate(value: Int64) -> NSDate {
        return NSDate(timeIntervalSince1970: Double(value / 1000))
    /// From seconds since 1 Jan 1970
    static func fromUnixTime(value: Int64) -> NSDate {
        return NSDate(timeIntervalSince1970: Double(value))

Happy coding...
Did this help?, then please help out a small independent.
If you decide that you want to make a small donation, you can do so by clicking this
link: a cup of coffee ($2) or use the popup on the right hand side for different amounts.
Payments will be processed by PayPal, receiver will be sales at balancingrock dot nl
Bitcoins will be gladly accepted at: 1GacSREBxPy1yskLMc9de2nofNv2SNdwqH

We don't get the world we wish for... we get the world we pay for.

No comments:

Post a Comment