Update, August 26, 2015: I’ve updated this article so that its code works with Swift 2. It compiles under the latest version of Xcode 7, beta 6.
In previous installments in this series, we’ve covered:
- The basics of dates and times in Swift, with creating dates, converting components into dates and vice versa, and converting dates into strings and vice versa,
- date arithmetic in Swift, with adding time intervals to dates and calculating the time between two dates, and
- making date arithmetic in Swift more Swift-like by harnessing the power of operator overloading and class extensions.
In this installment, we’ll make getting the time interval between two dates — which normally involves a lot of typing — a little more Swift-like.
One common date arithmetic operation is to determine the interval between two given dates. This is usually a clunky two-step process based on NSCalendar
‘s components
method, which expects at least three parameters:
- The time components you want the method to return, such as
year
s,month
s,day
s,hour
s,minute
s, andsecond
s. This is expressed by ORing togetherNSCalendarUnit
values, and - the two dates, in
NSDate
form.
Let’s look at how it works. First, we’ll need a couple of dates. Create a new playground and put the following code into it:
// Playground - noun: a place where people can play import UIKit let userCalendar = NSCalendar.currentCalendar() // Let's create some dates to work with // ==================================== // It's 3:45:30 a.m., New Year's Day. Time to go home. let goHomeYoureDrunkTimeComponents = NSDateComponents() goHomeYoureDrunkTimeComponents.year = 2015 goHomeYoureDrunkTimeComponents.month = 1 goHomeYoureDrunkTimeComponents.day = 1 goHomeYoureDrunkTimeComponents.hour = 3 goHomeYoureDrunkTimeComponents.minute = 45 goHomeYoureDrunkTimeComponents.second = 30 let goHomeYoureDrunkTime = userCalendar.dateFromComponents(goHomeYoureDrunkTimeComponents)! // Let's create an NSDate representing Bad Poetry Day (August 18) // at 4:20:10 p.m. let badPoetryDayComponents = NSDateComponents() badPoetryDayComponents.year = 2015 badPoetryDayComponents.month = 8 badPoetryDayComponents.day = 18 badPoetryDayComponents.hour = 16 badPoetryDayComponents.minute = 20 badPoetryDayComponents.second = 10 let badPoetryDay = userCalendar.dateFromComponents(badPoetryDayComponents)!
In your playground’s sidebar, you should see the string representations of those dates:
goHomeYoureDrunkTime
should display as something like January 1, 2015 at 3:45 a.m., andbadPoetryDay
should display as something like August 18, 2015 at 4:20 p.m..
Let’s find out how many days, hours, minutes, and seconds there are between goHomeYoureDrunkTime
and badPoetryDay
with the following code:
// (Previous code goes here) // How many days, hours, minutes, and seconds between // goHomeYoureDrunkTime and badPoetryDay? let dayHourMinuteSecond: NSCalendarUnit = [.Day, .Hour, .Minute, .Second] let difference = NSCalendar.currentCalendar().components( dayHourMinuteSecond, fromDate: goHomeYoureDrunkTime, toDate: badPoetryDay, options: []) difference.day // 229 difference.hour // 12 difference.minute // 34 difference.second // 40
You should see from difference that there are 229 days, 12 hours, 34 minutes, and 40 seconds between the two dates. We did a lot of typing to get this result, and there should be a nicer way to do it. How about this:
// (Previous code goes here) // A date subtraction operation that returns an NSDateComponents // instance specifying the days, hours, miniutes and seconds // between two given NSDates // ============================================================= func -(lhs: NSDate, rhs: NSDate) -> NSDateComponents { let dayHourMinuteSecond: NSCalendarUnit = [.Day, .Hour, .Minute, .Second] return NSCalendar.currentCalendar().components(dayHourMinuteSecond, fromDate: rhs, toDate: lhs, options: []) } // Let's test it: let diff = badPoetryDay - goHomeYoureDrunkTime diff.day // 229 diff.hour // 12 diff.minute // 34 diff.second // 40
With this code, we’ve overloaded the -
operator, so that when both its operands are NSDate
s, it returns an NSDateComponents
instance specifying the day
s, hour
s, minute
s, and second
s between the two. I could’ve coded it so that it also returned the time in terms of months and years, but the size of those units vary depending on the month and year, while days, hours, minutes, and seconds always represent the same amount of time.
Related articles
A very brief introduction to date formatting in Swift and iOS: The oversight in a mostly-good book on Swift programming led me down the path of writing articles about dates and times in Swift, starting with this one, where I look atNSDateFormatter
.
How to work with dates and times in Swift, part one: An introduction of Cocoa’s date and time classes, and how they work together. This article covers UTC (Coordinated Universal Time), and the key classes: NSDate
, NSCalendar
, NSDateComponents
.
How to work with dates and times in Swift, part two: Calculations with dates: Now that we’ve got the basics, it’s time to do some date arithmetic: comparing two dates to see which one is the earlier and later one, finding out how far apart two dates are, and adding and subtracting from dates.
How to work with dates and times in Swift, part three: Making date arithmetic more Swift-like: Cocoa’s date and time classes have an Objective-C heritage, which in the Swift context, feel kind of clunky. In this article, I look at ways — and by ways, I mean helper functions and class extensions — to make date calculations feel more like Swift.
3 replies on “How to work with dates and times in Swift, part four: A more Swift-like way to get the time interval between two dates [Updated for Swift 2]”
[…] How to work with dates and times in Swift, part four: A more Swift-like way to get the time interval… This quick article shows you how to make an operator overload that makes getting the time interval between two dates more like subtraction. […]
Thank you Joey for all the hard work and thank you for updating to Swift 2. I have read all 4 parts and there is a lot of very useful information for me in my app that needs to fire based on start date, day, start time and interval being set in NSUserDefaults.
Thank you this really usefully for me :) and thanks for the updating to swift 2