Categories
Swift Kick

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]

date and time

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.

swift kick

In previous installments in this series, we’ve covered:

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 years, months, days, hours, minutes, and seconds. This is expressed by ORing together NSCalendarUnit 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., and
  • badPoetryDay 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 NSDates, it returns an NSDateComponents instance specifying the days, hours, minutes, and seconds 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.

dates and times in swift - smallRelated 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]”

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.

Comments are closed.