NSDate comparison
iOS development
Swift programming
date handling
Objective-C

Comparing NSDates without time component

Master System Design with Codemia

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

Introduction

Comparing two dates by calendar day is a common requirement in iOS apps. You might want to group messages by day, disable a button for dates before today, or highlight whether two events happen on the same date regardless of hour and minute. The important detail is that a raw Date or NSDate value always includes time, so comparing them directly is usually the wrong tool.

Why Direct Equality Fails

A Date represents a precise point in time. That means these two values are different even though they fall on the same day for the user:

  • March 7 at 09:00
  • March 7 at 18:30

If you compare them with ==, the result is false because the timestamps differ.

In Swift, a direct comparison behaves like this:

swift
1let first = Date(timeIntervalSince1970: 1_709_800_000)
2let second = first.addingTimeInterval(60 * 60 * 3)
3
4print(first == second) // false

That is correct for exact timestamp comparison, but not for "same day" logic.

Compare by Calendar Components

The right way is to let a Calendar decide what counts as the same day in the current locale and time zone. Modern Swift provides a very clear API:

swift
1import Foundation
2
3let calendar = Calendar.current
4let date1 = Date()
5let date2 = Date().addingTimeInterval(60 * 60 * 5)
6
7if calendar.isDate(date1, inSameDayAs: date2) {
8    print("Same calendar day")
9} else {
10    print("Different days")
11}

This is preferred because it respects calendar rules, daylight-saving transitions, and the active time zone.

If you need ordering rather than equality, compare the start of each day:

swift
1import Foundation
2
3let calendar = Calendar.current
4let start1 = calendar.startOfDay(for: date1)
5let start2 = calendar.startOfDay(for: date2)
6
7if start1 < start2 {
8    print("date1 is earlier by calendar day")
9}

Normalizing both values to the start of their day lets you compare only the date portion in a stable, readable way.

Objective-C and NSDate

Older codebases often still use NSDate and NSCalendar. The idea is exactly the same: ask the calendar for day-level information instead of manually stripping components.

objective-c
1NSDate *firstDate = [NSDate date];
2NSDate *secondDate = [firstDate dateByAddingTimeInterval:60 * 60 * 8];
3NSCalendar *calendar = [NSCalendar currentCalendar];
4
5BOOL sameDay = [calendar isDate:firstDate inSameDayAsDate:secondDate];
6NSLog(@"%@", sameDay ? @"Same day" : @"Different day");

If you are targeting an older API surface, you can extract year, month, and day components and compare those values instead.

objective-c
1NSDateComponents *c1 = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay)
2                                   fromDate:firstDate];
3NSDateComponents *c2 = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay)
4                                   fromDate:secondDate];
5
6BOOL sameDay = c1.year == c2.year && c1.month == c2.month && c1.day == c2.day;

That approach is more verbose, but it is still better than formatting the date into a string just to compare text.

Time Zone Awareness Matters

The calendar day depends on time zone. A timestamp near midnight in UTC may still belong to the previous day for a user in Toronto and the next day for a user in Tokyo. That is why day comparisons should use the intended calendar and time zone explicitly when the business rule depends on them.

swift
1var calendar = Calendar(identifier: .gregorian)
2calendar.timeZone = TimeZone(identifier: "America/Toronto")!
3
4let sameDay = calendar.isDate(date1, inSameDayAs: date2)

This makes the rule deterministic and prevents bugs where tests pass on one machine and fail on another.

Common Pitfalls

The most common mistake is comparing Date values directly when the requirement is really "same day." Exact equality compares timestamps, not calendar dates.

Another mistake is converting dates to strings and comparing the strings. That is slower, locale-sensitive, and harder to maintain than using calendar APIs.

Developers also forget about time zones. A comparison that looks right in UTC can be wrong for the user's local day.

Finally, avoid manual math such as dividing timestamps by 86400. Day length is not always exactly 24 hours because of daylight-saving changes.

Summary

  • A Date or NSDate always includes time, so direct equality is usually too strict.
  • Use Calendar.isDate(_:inSameDayAs:) for same-day checks.
  • Use startOfDay(for:) when you need day-level ordering.
  • In Objective-C, NSCalendar provides the same day-based comparison tools.
  • Always consider time zone and calendar rules when comparing by date only.

Course illustration
Course illustration

All Rights Reserved.