Quantcast
Channel: NSHipster
Viewing all articles
Browse latest Browse all 382

TimeInterval, Date, and DateInterval

$
0
0

Nestled between Madrid’s Centro and Salamanca districts, just a short walk from the sprawling Buen Retiro Park, The Prado Museum boasts an extensive collection of works from Europe’s most celebrated painters. But if, during your visit, you begin to tire of portraiture commissioned by 17th-century Spanish monarchs, consider visiting the northernmost room of the 1st floor — Sala 002. There you’ll find this Baroque era painting by the French artist Simon Vouet.

You’d be forgiven for wondering why this pair of young women, brandishing a hook and spear, stand menacingly over a cowering old man while a mob of cherubim tears at his back. It is, of course, allegorical: reading the adjacent placard, you’ll learn that this piece is entitled Time defeated by Hope and Beauty. The old man? That’s Time. See the hourglass in his hand and scythe at his feet?

Take a moment, standing in front of this painting, to reflect on the enigmatic nature of time.

Think now about how our limited understanding of time is reflected in — or perhaps exacerbated by — the naming of the Foundation date and time APIs.

It’s about time we got them straight.


Seconds are the fundamental unit of time. They’re also the only unit that has a fixed duration.

Months vary in length (30 days hath September…), as do years (53 weeks hath 71 years every cycle of 400…) certain years pick up an extra day (leap years are misnamed if you think about it), and days gain and lose an hour from daylight saving time (thanks, Benjamin Franklin). And that’s to say nothing of leap seconds, which are responsible for such oddities as the 61 second minute, the 3601 second hour, and, of course, the 1209600 second fortnight.

TimeInterval (neé NSTimeInterval) is a typealias for Double that represents duration as a number of seconds. You’ll see it as a parameter or return type for APIs that deal with a duration of time. Being a double-precision floating-point number, TimeInterval can represent submultiples in its fraction, (though for anything beyond millisecond precision, you’ll want to use something else).

Date and Time

It’s unfortunate that the Foundation type representing time is named Date. Colloquially, one typically distinguishes “dates” from “times” by saying that the former has to do with calendar days and the latter has more to do with the time of day. But Date is entirely orthogonal from calendars, and contrary to its name represents an absolute point in time.

Another source of confusion for Date is that, despite representing an absolute point in time, it’s defined by a time interval since a reference date:

publicstructDate:ReferenceConvertible,Comparable,Equatable{publictypealiasReferenceType=NSDatefileprivatevar_time:TimeInterval// ...}

The reference date, in this case, is the first instant of January 1, 2001, Greenwich Mean Time (GMT).

Date Intervals and Time Intervals

DateInterval is a recent addition to Foundation. Introduced in iOS 10 and macOS Sierra, this type represents a closed interval between two absolute points in time (again, in contrast to TimeInterval, which represents a duration in seconds).

So what is this good for? Consider the following use cases:

Getting the Date Interval of a Calendar Unit

In order to know the time of day for a point in time — or what day it is in the first place — you need to consult a calendar. From there, you can determine the range of a particular calendar unit, like a day, month, or year. The Calendar method dateInterval(of:for:) makes this really easy to do:

letcalendar=Calendar.currentletdate=Date()letdateInterval=calendar.dateInterval(of:.month,for:date)

Because we’re invoking Calendar, we can be confident in the result that we get back. Look how it handles daylight saving transition without breaking a sweat:

letdstComponents=DateComponents(year:2018,month:11,day:4)calendar.dateInterval(of:.day,for:calendar.date(from:dstComponents)!)?.duration// 90000 seconds

It’s 2018-10-08 11:56:58 -0700. Don’t you think that it’s time you stopped hard-coding secondsInDay = 86400?

Calculating Intersections of Date Intervals

For this example, let’s return to The Prado Museum and admire its extensive collection of paintings by Rubens — particularly this apparent depiction of the god of Swift programming.

Rubens, like Vouet, painted in the Baroque tradition. The two were contemporaries, and we can determine the full extent of how they overlap in the history of art with the help of DateInterval:

importFoundationletcalendar=Calendar.current// Simon Vouet// 9 January 1590 – 30 June 1649letvouet=DateInterval(start:calendar.date(from:DateComponents(year:1590,month:1,day:9))!,end:calendar.date(from:DateComponents(year:1649,month:6,day:30))!)// Peter Paul Rubens// 28 June 1577 – 30 May 1640letrubens=DateInterval(start:calendar.date(from:DateComponents(year:1577,month:6,day:28))!,end:calendar.date(from:DateComponents(year:1640,month:5,day:30))!)letoverlap=rubens.intersection(with:vouet)!calendar.dateComponents([.year],from:overlap.start,to:overlap.end)// 50 years

According to our calculations, there was a period of 50 years where both painters were living.

We can even take things a step further and use DateIntervalFormatter to provide a nice representation of that time period:

letformatter=DateIntervalFormatter()formatter.timeStyle=.noneformatter.dateTemplate="%Y"formatter.string(from:overlap)// "1590 – 1640"

Beautiful. You might as well print this code out, frame it, and hang it next to The Judgement of Paris.


The fact is, we still don’t really know what time is (or if it even actually exists). But I’m hopeful that we, as developers, will find the beauty in Foundation’s Date APIs, and in time, learn how to overcome our lack of understanding.

That does it for this week’s article. See you all next time.


Viewing all articles
Browse latest Browse all 382

Trending Articles