NSDateFormatter vs NSCalendar for DST Transition Ambiguities
0 reputation · 14 Apr 2020, 00:21 UTC
0 reputation · 14 Apr 2020, 00:21 UTC
When converting regional date and time data to a UTC-based NSDate, Objective-C provides two primary paths: NSDateFormatter for string-based parsing and NSCalendar with NSDateComponents for programmatic construction.
A critical challenge arises during Daylight Saving Time (DST) transitions, specifically during 'fold' periods where a local time occurs twice or 'gap' periods where a local time does not exist. While NSDateFormatter simplifies the conversion by applying the NSTimeZone rules to a formatted string, NSCalendar offers more granular control over individual date components.
Because NSDate objects are time-zone agnostic and store only UTC, the method used to derive the date determines how these ambiguities are resolved. There is no universal framework policy to automatically enforce whether a duplicated hour refers to the first or second occurrence during a transition.
NSCalendar offer a mechanism to explicitly define the fold occurrence that NSDateFormatter lacks?35275 reputation · 14 Apr 2020, 01:09 UTC
NSCalendar provides more reliable and deterministic behavior for DST overlap times. NSDateFormatter has no public API to choose which occurrence of a repeated wall time to use, while NSCalendar exposes repeatedTimePolicy to explicitly select first or last occurrence.
date(bySettingHour:minute:second:ofDate:matchingPolicy:repeatedTimePolicy:direction:) with options .first, .last and .unspecified, allowing deterministic resolution of ambiguous wall times.For reliable DST-aware conversion, parse the input string to components with NSDateFormatter then build the absolute Date with NSCalendar using the desired repeatedTimePolicy and the correct timeZone. This separates string interpretation from instant resolution.
Ensure calendar.timeZone matches the zone of the wall time. Mixing NSDateFormatter and NSCalendar with different timeZones can produce off-by-one-hour errors around DST transitions.
One diagnostic detail changes the recommendation: is the input a fall-back repeated hour or a spring-forward non-existent gap? repeatedTimePolicy resolves repeats, while non-existent times need a different matching strategy and policy choice.
Use comments to ask for clarification. Post a solution as an answer.
35,275 reputation · 14 Apr 2020, 02:39 UTC
While repeatedTimePolicy resolves ambiguous (fold) times, NSCalendar also requires a matchingPolicy (e.g., .nextTime, .previousTime, .strict) to handle gap times that do not exist during a spring‑forward transition. NSDateFormatter provides no analogous policy; if the input string represents a gap time, the formatter cannot produce a valid NSDate and you must fall back to component‑based construction with the appropriate matchingPolicy. Additionally, embedding a UTC offset in the format string (for example, yyyy-MM-dd HH:mm:ss Z) makes the formatter treat the value as an absolute instant, removing ambiguity, but this only works when the offset is present in the source data.