Swift
Date Calculation
Date Difference
Programming Tutorial
iOS Development

Calculating the difference between two dates in Swift

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Date arithmetic in Swift is straightforward once you use the right Foundation APIs, but the right API depends on the question you are asking. Sometimes you want elapsed time between two moments, and sometimes you want calendar components such as days, months, or years as users would understand them.

Date Represents a Moment, Not a Calendar Label

In Swift, Date is an absolute point in time. It does not contain a calendar, locale, or time zone by itself. Human concepts such as “3 days later” come from Calendar, which interprets those moments.

That is why date difference code usually starts with two pieces:

  • 'Date values for the start and end moments'
  • a Calendar value that defines how to count days, months, or years

If you only compare timestamps, timeIntervalSince may be enough. If you want day or month components, use Calendar.dateComponents.

Counting Day Differences with Calendar

For user-facing day counts, this is the most common pattern:

swift
1import Foundation
2
3let formatter = DateFormatter()
4formatter.dateFormat = "yyyy-MM-dd"
5formatter.timeZone = TimeZone(secondsFromGMT: 0)
6
7let start = formatter.date(from: "2025-09-01")!
8let end = formatter.date(from: "2025-09-10")!
9
10let calendar = Calendar(identifier: .gregorian)
11let components = calendar.dateComponents([.day], from: start, to: end)
12
13print(components.day ?? 0)

This prints 9. The calculation is done by Calendar, which understands date boundaries correctly.

If you need more than one component, request them together:

swift
1import Foundation
2
3let formatter = DateFormatter()
4formatter.dateFormat = "yyyy-MM-dd"
5formatter.timeZone = TimeZone(secondsFromGMT: 0)
6
7let start = formatter.date(from: "2025-01-15")!
8let end = formatter.date(from: "2026-03-20")!
9
10let calendar = Calendar(identifier: .gregorian)
11let difference = calendar.dateComponents([.year, .month, .day], from: start, to: end)
12
13print(difference.year ?? 0)
14print(difference.month ?? 0)
15print(difference.day ?? 0)

That is useful for age displays, subscription periods, and countdowns.

Measuring Exact Elapsed Time

If your question is about exact duration rather than calendar components, use timeIntervalSince:

swift
1import Foundation
2
3let formatter = ISO8601DateFormatter()
4let start = formatter.date(from: "2025-09-01T12:00:00Z")!
5let end = formatter.date(from: "2025-09-03T18:00:00Z")!
6
7let seconds = end.timeIntervalSince(start)
8let days = seconds / 86_400
9
10print(seconds)
11print(days)

This returns a TimeInterval, which is a number of seconds. It is the right choice for metrics, timeouts, or internal duration calculations.

Do not confuse it with calendar-day difference. Two timestamps can cross into a new date while still being less than 24 hours apart.

Parsing Dates Safely

Many bugs in Swift date calculations come from parsing, not subtraction. If two strings are parsed under different assumptions, the subtraction result will be wrong even if the difference code itself is fine.

A safe pattern is to pin the formatter’s time zone and format explicitly:

swift
1import Foundation
2
3func makeFormatter() -> DateFormatter {
4    let formatter = DateFormatter()
5    formatter.calendar = Calendar(identifier: .gregorian)
6    formatter.locale = Locale(identifier: "en_US_POSIX")
7    formatter.timeZone = TimeZone(secondsFromGMT: 0)
8    formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
9    return formatter
10}
11
12let formatter = makeFormatter()
13let start = formatter.date(from: "2025-09-01 08:00:00")!
14let end = formatter.date(from: "2025-09-04 10:30:00")!
15
16let duration = end.timeIntervalSince(start)
17print(duration)

Using en_US_POSIX and a fixed time zone is especially helpful when parsing machine-formatted dates.

Time Zones and Calendar Boundaries

If your app shows day differences to users, the chosen time zone matters. Midnight in Toronto and midnight in UTC are different moments. A date pair can produce one answer in UTC and another in a local time zone if it crosses a boundary differently.

When the requirement is “how many calendar days passed for this user,” use a Calendar configured with the relevant time zone. When the requirement is “how many seconds elapsed,” compare absolute Date values directly.

This is also why daylight saving transitions can surprise people. A local “day” may contain 23 or 25 hours, but Calendar can still report that one calendar day passed.

Common Pitfalls

A frequent mistake is using timeIntervalSince when the business rule actually wants calendar days. That works for exact duration but can produce surprising results around midnight or daylight saving changes.

Another issue is leaving DateFormatter settings implicit. Locale, time zone, and calendar defaults may vary between environments.

Force-unwrapping parsed dates is acceptable in short examples, but production code should handle invalid input gracefully.

Finally, developers sometimes forget that Date itself has no calendar meaning. User-facing differences usually need Calendar, not raw seconds alone.

Summary

  • Use Calendar.dateComponents for calendar-aware differences such as days, months, or years.
  • Use timeIntervalSince for exact elapsed duration in seconds.
  • Configure DateFormatter explicitly so parsing is deterministic.
  • Choose the time zone based on the business rule, especially for user-facing day counts.
  • Treat timestamp math and calendar math as related but different problems.

Course illustration
Course illustration

All Rights Reserved.