NSDate
date calculation
programming
Swift
iOS development

Number of days between two NSDates

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Calculating day differences between two NSDate values sounds simple, but timezone changes, daylight saving transitions, and time components can produce surprising results. The reliable approach is to decide whether you need calendar day distance or exact elapsed time in seconds. Once that choice is clear, Foundation APIs make the implementation straightforward.

Calendar Days Versus Elapsed Time

A common mistake is dividing raw seconds by 86400 and assuming that always equals one day. That works for many cases, but it can break around daylight saving boundaries where a day may not have exactly that duration in local time. If your requirement is calendar day difference, use NSCalendar or modern Calendar calculations.

swift
1import Foundation
2
3let formatter = DateFormatter()
4formatter.dateFormat = "yyyy-MM-dd HH:mm"
5formatter.timeZone = TimeZone(identifier: "America/Toronto")
6
7let start = formatter.date(from: "2026-03-01 23:30")!
8let end = formatter.date(from: "2026-03-03 00:30")!
9
10let calendar = Calendar.current
11let startDay = calendar.startOfDay(for: start)
12let endDay = calendar.startOfDay(for: end)
13let days = calendar.dateComponents([.day], from: startDay, to: endDay).day!
14
15print(days) // 2

By anchoring both dates to startOfDay, you remove hour and minute noise and count true day boundaries in the selected calendar.

Legacy Objective C Pattern with NSDate

If you maintain older iOS code, the same logic works with Objective C APIs. Normalize to midnight first, then request .day components from the calendar.

objective-c
1NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
2formatter.dateFormat = @"yyyy-MM-dd HH:mm";
3formatter.timeZone = [NSTimeZone timeZoneWithName:@"America/Toronto"];
4
5NSDate *start = [formatter dateFromString:@"2026-03-01 23:30"];
6NSDate *end = [formatter dateFromString:@"2026-03-03 00:30"];
7
8NSCalendar *calendar = [NSCalendar currentCalendar];
9NSDate *startDay = [calendar startOfDayForDate:start];
10NSDate *endDay = [calendar startOfDayForDate:end];
11
12NSDateComponents *components = [calendar components:NSCalendarUnitDay
13                                            fromDate:startDay
14                                              toDate:endDay
15                                             options:0];
16NSLog(@"%ld", (long)components.day);

This pattern is stable and easy to test. It is also explicit about timezone handling, which prevents region dependent bugs in distributed teams.

Choosing the Right Definition in Business Logic

Many production defects come from not agreeing on what a day means. Billing systems often need calendar day boundaries in a specific timezone, while analytics pipelines may need exact elapsed duration in UTC. Document this rule near the function and encode it in tests with boundary dates.

A practical strategy is to provide two utility methods, one for calendar day difference and one for elapsed hours or seconds. Callers then choose intentionally instead of guessing from one ambiguous helper.

swift
1func calendarDaysBetween(_ a: Date, _ b: Date, calendar: Calendar) -> Int {
2    let aDay = calendar.startOfDay(for: a)
3    let bDay = calendar.startOfDay(for: b)
4    return calendar.dateComponents([.day], from: aDay, to: bDay).day ?? 0
5}
6
7func elapsedHoursBetween(_ a: Date, _ b: Date) -> Int {
8    Int(b.timeIntervalSince(a) / 3600)
9}

Testing Edge Dates and Timezones

Date logic should always be validated with edge cases, not only normal weekdays. Build a small test matrix that includes month boundaries, leap years, and daylight saving changes for the timezone your product uses. This catches most regressions before they reach users.

swift
1let tz = TimeZone(identifier: "America/Toronto")!
2var cal = Calendar(identifier: .gregorian)
3cal.timeZone = tz
4
5let f = DateFormatter()
6f.dateFormat = "yyyy-MM-dd HH:mm"
7f.timeZone = tz
8
9let cases = [
10    ("2026-03-07 12:00", "2026-03-09 12:00"),
11    ("2026-02-28 10:00", "2026-03-01 10:00"),
12]
13
14for (a, b) in cases {
15    let d1 = f.date(from: a)!
16    let d2 = f.date(from: b)!
17    print(a, b, calendarDaysBetween(d1, d2, calendar: cal))
18}

Treat these tests as product requirements, not implementation details. When rules change, update tests first, then update helper code.

Common Pitfalls

  • Dividing seconds by 86400 when business rules require calendar boundaries.
  • Ignoring timezone selection, which leads to different results across environments.
  • Comparing raw dates with different hour values when only the day part matters.
  • Mixing local time logic and UTC logic in the same helper.
  • Skipping tests around daylight saving transitions and month boundaries.

Summary

  • Decide first whether you need calendar days or elapsed duration.
  • Use startOfDay and calendar components for calendar day math.
  • Keep timezone handling explicit in formatters and calculations.
  • Support legacy NSDate code with the same normalization strategy.
  • Add boundary tests so date math remains stable over time.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.