Swift
DateManipulation
DateDifference
Programming
iOSDevelopment

Getting the difference between two Dates months/days/hours/minutes/seconds in Swift

Interview Questions practice on Codemia

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

Browse interview questions

Introduction

Date differences in Swift look simple until the requirement says "show months, days, hours, minutes, and seconds." At that point you have to decide whether you want a calendar-aware difference, which respects month lengths and daylight saving changes, or a fixed-duration difference based only on elapsed seconds.

Use Calendar.dateComponents for Calendar-Aware Differences

If you want output such as "1 month, 2 days, 3 hours," use Calendar.dateComponents. This method understands the calendar rules for the locale and timezone you provide.

swift
1import Foundation
2
3var calendar = Calendar(identifier: .gregorian)
4calendar.timeZone = TimeZone(secondsFromGMT: 0)!
5
6let formatter = ISO8601DateFormatter()
7let start = formatter.date(from: "2026-01-15T08:30:00Z")!
8let end = formatter.date(from: "2026-02-18T10:45:20Z")!
9
10let components = calendar.dateComponents(
11    [.month, .day, .hour, .minute, .second],
12    from: start,
13    to: end
14)
15
16print(components.month ?? 0)
17print(components.day ?? 0)
18print(components.hour ?? 0)
19print(components.minute ?? 0)
20print(components.second ?? 0)

This is the standard solution for user-facing date differences. It answers a calendar question, not a pure arithmetic one.

Build a Reusable Helper

A helper function makes the difference logic easier to test and keeps your UI code clean.

swift
1import Foundation
2
3func difference(from start: Date, to end: Date, calendar: Calendar) -> DateComponents {
4    calendar.dateComponents([.month, .day, .hour, .minute, .second], from: start, to: end)
5}
6
7var calendar = Calendar(identifier: .gregorian)
8calendar.timeZone = TimeZone(identifier: "America/Toronto")!
9
10let start = Date(timeIntervalSince1970: 1_700_000_000)
11let end = start.addingTimeInterval(3_700_000)
12let diff = difference(from: start, to: end, calendar: calendar)
13
14print(diff)

Returning DateComponents instead of a preformatted string gives you more flexibility. One screen may want abbreviated output while another needs a verbose sentence.

Use timeIntervalSince for Fixed Durations

Sometimes you do not care about months or calendar boundaries. For timers, telemetry, and elapsed durations, a fixed number of seconds is often the correct source of truth.

swift
1import Foundation
2
3let start = Date(timeIntervalSince1970: 1_700_000_000)
4let end = start.addingTimeInterval(9_061)
5
6let seconds = Int(end.timeIntervalSince(start))
7let hours = seconds / 3600
8let minutes = (seconds % 3600) / 60
9let remainingSeconds = seconds % 60
10
11print("\(hours)h \(minutes)m \(remainingSeconds)s")

This is not a substitute for month-aware date math. You cannot derive a meaningful calendar month count from raw seconds because months do not all have the same length.

Formatting the Result for Display

Once you have the components, format them separately from the calculation. Swift provides DateComponentsFormatter for this job.

swift
1import Foundation
2
3let formatter = DateComponentsFormatter()
4formatter.allowedUnits = [.day, .hour, .minute, .second]
5formatter.unitsStyle = .abbreviated
6formatter.zeroFormattingBehavior = .dropLeading
7
8let duration: TimeInterval = 93_784
9print(formatter.string(from: duration) ?? "")

DateComponentsFormatter is convenient for fixed durations. For fully calendar-aware month and day output, you may still prefer to compute DateComponents yourself and format the individual fields explicitly.

Timezone and Daylight Saving Matter

A common source of confusion is comparing dates parsed in different timezones or letting Calendar.current decide behavior implicitly. If your inputs come from servers, logs, or APIs, parse them in a known timezone and use a calendar with an explicit timezone.

Crossing a daylight saving boundary can change the hour count even when the dates look like they are exactly one day apart on the calendar. That is not a Swift bug; it is real civil time behavior. If your product requirement says "calendar days" use calendar math. If it says "exact elapsed hours" use timeIntervalSince.

Common Pitfalls

One mistake is using fixed-second arithmetic when the requirement is calendar-aware. That works for countdown timers but fails for month and day reporting.

Another issue is ignoring timezone configuration. Two Date values represent exact instants, but the way you break them into months, days, and hours depends on the calendar and timezone used for the comparison.

Developers also often return formatted strings too early. If the calculation and formatting are coupled together, localization and testing become harder.

Finally, watch reversed inputs. If end is earlier than start, the resulting components may be negative. Decide whether your API should preserve that or normalize the order first.

Summary

  • Use Calendar.dateComponents when you need months, days, and other calendar-aware parts.
  • Use timeIntervalSince when you need a fixed elapsed duration.
  • Set calendar and timezone explicitly for predictable results.
  • Return DateComponents from helpers and format separately for UI output.
  • Treat daylight saving transitions and reversed date ranges as deliberate design cases, not afterthoughts.

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.