The NSDateInterval Object

Somehow, this shiny new object, which was actually introduced in iOS 10, flew past my radar. Today I want to take a few minutes to talk about the `NSDateInterval`

object. This object allows us to quickly calculate the time interval (represented as a `NSTimeInterval`

) between dates, it allows us to check if two dates overlap, and it allows us to check if a given date is within a certain interval.

# The NSDateInterval Class

This small object is made of a handful of property and functions.

To create a `NSDateInterval`

, you can provide either a closed range with the start and end date, or you can provide the start date with a duration. In the example below we will use two dates, seven days apart.

```
let now = Date()
let components = DateComponents(day: 7)
if let sevenDaysAhead = Calendar.current.date(byAdding: components, to: now) {
let interval = DateInterval(start: now, end: sevenDaysAhead)
}
```

Our `internal`

variable now has a couple of handful properties. You can get the `startDate`

and `endDate`

, but perhaps most interesting the `duration`

, which contains the number of seconds between both dates.

Having the duration can be useful on its own, but what’s even more useful is that we can now compare and check if said date intervals intersect, or if a date is part of a certain date interval.

## Comparing Date Intervals

To compare two `DateIntervals`

, simply call `compare(_)`

on one of them and pass it the second interval. This operation will return a `ComparisonResult`

which will let you know which one is “bigger” than the other.

```
let now = Date()
let components = DateComponents(day: 7)
if let sevenDaysAhead = Calendar.current.date(byAdding: components, to: now) {
let interval = DateInterval(start: now, end: sevenDaysAhead)
// Let's create a differemt but similar interval, but eight months ago
let eightMonthsAgoComponents = DateComponents(month: -8)
if let eightMonthsAgo = Calendar.current.date(byAdding: eightMonthsAgoComponents, to: now),
let eightMonthsAgoPlus7Days = Calendar.current.date(byAdding: DateComponents(day: 7), to: eightMonthsAgo){
let interval8MonthsAgo = DateInterval(start: eightMonthsAgo, end: eightMonthsAgoPlus7Days)
let comparison = interval.compare(interval8MonthsAgo)
switch comparison {
case .orderedAscending: print("orderedAscending")
case .orderedDescending: print("orderedDescending")
case .orderedSame: print("orderedSame")
}
}
}
```

This is a bit of a mouthful, but essentially what it does is:

- Create an interval between the current day and the date seven days in the future.
- Create a date 8 months in the past, create a date 7 days after that day in the past, and create an interval with the two.
- Compare them.

The result will be `.orderedDescending`

, since the left side of the operation (`interval`

) is more recent than `interval8MonthsAgo`

. When comparing, the framework takes into account the `startDate`

and the `duration`

if necessary. The documentation on comparing intervals has more info.

## Equality of DateIntervals

We can check if two intervals are equal by using the `==`

operator (the documentation incorrectly states that there is a `isEqual`

function, but I wasn’t able to access it.

Two `DateInterval`

s are considered equal when their `startDate`

and `duration`

properties are the same.

```
let equalIntervals = interval == interval8MonthsAgo // false
```

The take away from the last two sections is that equality and comparison takes into account the `startDate`

and `duration`

properties in order to do their calculations. If you need to see if two date ranges are the same duration, but they don’t overlap or have any relation with each other, use `Calendar`

's `Calendar.current.dateComponents((_from:to:)`

method instead.

```
let difference = Calendar.current.dateComponents([.day], from: now, to: eightMonthsAgo) // -242 days ago (feel free to use abs() for the absolute value
```

## Checking Interval Intersections

You can check if two `DateInterval`

s intersect by calling the `intersects(_)`

method in one of them.

```
let now = Date()
if let sevenDaysAhead = Calendar.current.date(byAdding: DateComponents(day: 7), to: now),
let sixDaysAhead = Calendar.current.date(byAdding: DateComponents(day: 6), to: now),
let eightDaysAhead = Calendar.current.date(byAdding: DateComponents(day: 8), to: now),
let ninetDaysAhead = Calendar.current.date(byAdding: DateComponents(day: 9), to: eightDaysAhead){
let sevenDayInterval = DateInterval(start: now, end: sevenDaysAhead)
let sixDayInterval = DateInterval(start: now, end: sixDaysAhead)
let eightDaysInterval = DateInterval(start: now, end: eightDaysAhead)
let sevenAndSixIntersect = sevenDayInterval.intersects(sixDayInterval) // true
let sevenAndEightIntersect = sevenDayInterval.intersects(eightDaysInterval) // true
let farAwayInterval = DateInterval(start: eightDaysAhead, end: ninetDaysAhead)
let sevenDaysIntervalIntersectsFarAwayInterval = sevenDayInterval.intersects(farAwayInterval) // false
}
```

And, you can also find the interval at which two date intervals intersect, by calling `intersection(with:)`

on either one.

```
import Foundation
let now = Date()
if let sevenDaysAhead = Calendar.current.date(byAdding: DateComponents(day: 7), to: now),
let sixDaysAhead = Calendar.current.date(byAdding: DateComponents(day: 6), to: now),
let eightDaysAhead = Calendar.current.date(byAdding: DateComponents(day: 8), to: now),
let ninetDaysAhead = Calendar.current.date(byAdding: DateComponents(day: 9), to: eightDaysAhead){
let sevenDayInterval = DateInterval(start: now, end: sevenDaysAhead)
let eightDaysInterval = DateInterval(start: now, end: eightDaysAhead)
if let intersectionInterval = sevenDayInterval.intersection(with: eightDaysInterval) {
print("The intervals intersect starting on \(intersectionInterval.start) and ending on \(intersectionInterval.end)")
}
}
```

## Checking if a date exists within an interval.

Finally, the last useful thing we can do is to check if a single date fits in an interval. For this, simply call `contains(_)`

.

```
let now = Date()
if let sevenDaysAhead = Calendar.current.date(byAdding: DateComponents(day: 7), to: now),
let sixDaysAhead = Calendar.current.date(byAdding: DateComponents(day: 6), to: now),
let sevenDaysAndASecondAhead = Calendar.current.date(byAdding: DateComponents(day: 7, second: 1), to: now) {
let intervalSevenDaysAhead = DateInterval(start: now, end: sevenDaysAhead)
let containsSixDaysAhead = intervalSevenDaysAhead.contains(sixDaysAhead)
let containsSevenDaysAndASecondAhead = intervalSevenDaysAhead.contains(sevenDaysAndASecondAhead)
}
```

# Conclusion

If there is one thing Apple likes to do, is to make dealing with dates a simple affair for us. All their date-related APIs are packed with functionality to make calculation and manipulation of time-related data really easily. 5 years ago, Apple added `NSDateInterval`

to their collection of date tools, and it’s amazing how simple it is to work date intervals with it.

If you find any inaccuracies (and that includes typos) or problems in this article please tweet at me (@AndyIbanezK) or send me an e-mail to website[at]andyibanez[dot]com.

Please do not e-mail to ask me to cross-promote your website or any other soliciting of that kind. AndyIbanez.com is a personal blog, and unless there's a chance to enter a sponsorship relationship with you, I may ignore your message.

Thank you for helping me improve the quality of my blog!