Calendar.current.date(byAdding: .day, value: 1, to: someDate). It returns an optional Date and handles month ends, year ends, leap years and daylight saving changes. Avoid adding 86,400 seconds, because not every calendar day is 24 hours long.Why this happens
A Date in Swift (and NSDate in Objective-C) is a single point in time. Internally it is a number of seconds since a reference date. It has no concept of days, months or years. Those only exist when you interpret the date through a Calendar and a TimeZone.
That is why the obvious shortcut, date.addingTimeInterval(86400), is a trap. It adds exactly 24 hours, but a calendar day is not always 24 hours long. On a daylight saving transition day a day can be 23 or 25 hours. If you add 86,400 seconds to midnight on the day before clocks spring forward, you get 1:00 AM the next day instead of midnight. On the day clocks fall back, you can land at 11:00 PM on the same calendar day.
Calendar does date arithmetic in calendar units. Asking it for “one day later” gives you the same wall-clock time on the next calendar day. It also handles rollovers such as 21 February 2011 to 22 February 2011, or 31 December 2011 to 1 January 2012.
How to fix it
1. Use Calendar.date(byAdding:value:to:)
This is the shortest correct solution, and the one most developers should use:
import Foundation
let today = Date()
if let tomorrow = Calendar.current.date(byAdding: .day, value: 1, to: today) {
print(tomorrow)
}
Notes:
- The result is
Date?. In practice it rarely fails for.day, but unwrap it properly rather than force-unwrapping in production code. - Use a negative value to go back.
value: -1gives yesterday. - The same call works for
.hour,.weekOfYear,.month,.yearand otherCalendar.Componentvalues.
2. Use DateComponents when you add more than one unit
The accepted answer on the original question builds a DateComponents value. This form is useful when you want to add several units in one step, such as 1 day and 2 hours:
import Foundation
var offset = DateComponents()
offset.day = 1 // use -1 for yesterday
offset.hour = 2
let calendar = Calendar.current
let later = calendar.date(byAdding: offset, to: Date())
print(later as Any)
For a single day, option 1 is cleaner. Both forms go through the same calendar logic.
3. Wrap it in a small extension
If you do this in many places, a helper keeps call sites readable. It also lets you inject a specific calendar in tests:
import Foundation
extension Date {
func adding(days: Int, calendar: Calendar = .current) -> Date? {
calendar.date(byAdding: .day, value: days, to: self)
}
}
let tomorrow = Date().adding(days: 1)
let lastWeek = Date().adding(days: -7)
4. Verify the rollover cases with a fixed calendar
To confirm the month and year rollover, build the dates explicitly. Use a calendar pinned to a known time zone so the output does not depend on the machine running the code:
import Foundation
var utc = Calendar(identifier: .gregorian)
utc.timeZone = TimeZone(identifier: "UTC")!
let newYearsEve = utc.date(from: DateComponents(year: 2011, month: 12, day: 31))!
let next = utc.date(byAdding: .day, value: 1, to: newYearsEve)!
let parts = utc.dateComponents([.year, .month, .day], from: next)
print(parts.year!, parts.month!, parts.day!) // 2012 1 1
This is also a good pattern for unit tests. Never assert on Date() directly.
5. Get the start of the next day instead of “now plus a day”
Sometimes you don’t want “tomorrow at the current time”. You want “tomorrow at midnight”, for example to group items by day or schedule something for the next morning. Combine startOfDay(for:) with the addition:
import Foundation
let calendar = Calendar.current
let startOfToday = calendar.startOfDay(for: Date())
let startOfTomorrow = calendar.date(byAdding: .day, value: 1, to: startOfToday)
Use startOfDay(for:) instead of setting the hour to 0 yourself. In a few time zones, midnight does not exist on the day of a DST change, and startOfDay(for:) accounts for that.
6. Objective-C equivalent
In Objective-C, use NSCalendar. The unit-based method is the closest match to the Swift version:
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *tomorrow = [calendar dateByAddingUnit:NSCalendarUnitDay
value:1
toDate:[NSDate date]
options:0];
NSLog(@"tomorrow: %@", tomorrow);
The component-based form works too:
NSDateComponents *dayComponent = [[NSDateComponents alloc] init];
dayComponent.day = 1;
NSDate *nextDate = [[NSCalendar currentCalendar] dateByAddingComponents:dayComponent
toDate:[NSDate date]
options:0];
A note on “wrong” printed output
If the result looks off by a few hours, the arithmetic is probably fine. print(date) shows the date in UTC, not your local time zone. Format the date for display instead:
import Foundation
if let tomorrow = Calendar.current.date(byAdding: .day, value: 1, to: Date()) {
let formatter = DateFormatter()
formatter.dateStyle = .full
formatter.timeStyle = .short
print(formatter.string(from: tomorrow))
}
How to prevent it
- Do date arithmetic in calendar units through
Calendar. Don’t multiply seconds yourself. - Treat
addingTimeIntervalas “elapsed time”, such as a 30-second timeout. It does not mean calendar days. - Pass the
Calendar(and its time zone) into date helpers so tests can use a fixed calendar. - Use
startOfDay(for:)when you mean “the day”, not “this moment”. - Format dates with
DateFormatterorformatted()before showing or comparing them visually. Rawprintoutput is UTC.
FAQ
Is addingTimeInterval(60 * 60 * 24) ever acceptable?
Only when you truly mean “exactly 24 hours of elapsed time”, such as an expiry measured in hours. If you mean “the same time tomorrow” or “the next calendar day”, it breaks around daylight saving changes. Use Calendar for those cases.
What does the wrappingComponents parameter do?
date(byAdding:value:to:wrappingComponents:) defaults to false, which lets larger units roll over. With that default, 31 December plus one day becomes 1 January of the next year. If you pass true, only the day changes and the month stays the same. That means 31 December plus one day wraps to 1 December, which is rarely what you want.
Should I use Calendar.current or a specific calendar?
Use Calendar.current for user-facing dates so the result respects the user’s calendar and time zone. For server timestamps, tests or anything that must be reproducible, create a calendar such as Calendar(identifier: .gregorian) and set its timeZone explicitly.
Parts of this guide are adapted from content licensed under CC BY-SA 4.0; this article is shared under the same license.
