swiftdatecalendardoubledatecomponents

Add float/double days to Date?


There are similar questions but all of them about adding integer number of days to date. But what if I need to add 0.5 day for example?

In other words the following code won't work

let days: Double = 0.5
let date = Calendar.current.date(byAdding: .day, value: days, to: Date())

because:

public func date(byAdding components: DateComponents, to date: Date, wrappingComponents: Bool = false) -> Date?
public func date(byAdding component: Calendar.Component, value: Int, to date: Date, wrappingComponents: Bool = false) -> Date?

public struct DateComponents : ReferenceConvertible, Hashable, Equatable, Sendable {
...
public init(calendar: Calendar? = nil, timeZone: TimeZone? = nil, era: Int? = nil, year: Int? = nil, month: Int? = nil, day: Int? = nil, hour: Int? = nil, minute: Int? = nil, second: Int? = nil, nanosecond: Int? = nil, weekday: Int? = nil, weekdayOrdinal: Int? = nil, quarter: Int? = nil, weekOfMonth: Int? = nil, weekOfYear: Int? = nil, yearForWeekOfYear: Int? = nil)
...
}

int values everywhere only


Solution

  • The Calendar class's calendrical calculations like date(byAdding:to:wrappingComponents:) are written to handle lots of different edge cases like leap years, transitions between daylight savings and standard time, etc.

    Allowing fractional units would introduce ambiguity to such functions and might make them unreliable in certain edge cases. (e.g. on a day that includes a transition from standard time to daylight standard time, what is .5 day? 12 hours? (24+2)/2 or 13 hours?

    If you add 12 integer hours to a Date, the Calendar object can return a result that handles that specific case and is correct. Adding half-a-day the answer is "it depends".

    Edit:

    I would suggest factoring your code so that you can express the amount you need to add to a Date as an Integer CalendarComponent unit (e.g. hours or minutes for 1/2 day) and then still use the Calendar method date(byAdding:value:to:wrappingComponents:) to add integer units to your Date. It is very likely that there are edge cases that the Calendar class handles that you will miss if you try to do the calculations yourself.

    "Calendrical calculations" are messy and full of edge cases. Apple's Calendar class is rich, robust, and well tested. It is likely to handle edge cases that don't even occur to most of us.