66// Copyright © 2020 Klassen Software Solutions. All rights reserved.
77//
88
9+ #if canImport(os)
10+ import os
11+ #endif
12+
913import Foundation
1014
1115
1216/**
1317 Create a duration of the given units and return it as a `TimeInterval.`
18+ - warning: The resulting time interval will be approximate, using the assumptions described
19+ for the `DurationUnit`.
1420 */
1521public func duration( _ count: Double , _ unit: DurationUnit ) -> TimeInterval {
1622 return count * unit. rawValue
1723}
1824
1925
26+ /**
27+ Create a duration of the given units and return it as a `TimeInterval.` This version creates a duration
28+ assuming the given starting time and will take into account the correct calendar information in terms
29+ of days of the month and so on. If the calendar cannot compute an appropriate interval, then `nil` is
30+ returned.
31+ - warning: This uses the user's current calendar for the computation. This may lead to slightly
32+ different results for different calendars. For example, crossing daylight savings time gives answers
33+ that differ by an hour for calendars that take daylight savings into account.
34+ */
35+ public func duration( _ count: Int , _ unit: DurationUnit , from start: Date = Date ( ) ) -> TimeInterval ? {
36+ var component = DateComponents ( )
37+ switch unit {
38+ case . seconds: component. second = count
39+ case . minutes: component. minute = count
40+ case . hours: component. hour = count
41+ case . days: component. day = count
42+ case . weeks: component. day = count * 7
43+ case . months: component. month = count
44+ case . years: component. year = count
45+ }
46+
47+ guard let newDate = Calendar . current. date ( byAdding: component, to: start) else {
48+ os_log ( " warning: could not compute the requested interval, using an approximation " )
49+ return nil
50+ }
51+
52+ return newDate. timeIntervalSince ( start)
53+ }
54+
2055/**
2156 Enumeration to specify the unit of a given duration. The raw value of the enumeration is a TimeInterval
2257 that specifies the conversion from this unit into seconds.
2358
2459 - warning:
2560 This conversion is only approximate and does not consider leap years or even the difference between
26- months. For example, one year will always be considered 365 days and one month will always be considered
27- 30 days. For more accurate durations you will need to use the `Date` and related classes directly .
61+ months. Most of the time this will not matter, but if the more accurate conversion fails, these values will
62+ be used as a fallback mechanism for generating the interval .
2863 */
2964public enum DurationUnit : TimeInterval {
3065 /// Conversion of one second to a `TimeInterval`
@@ -38,7 +73,7 @@ public enum DurationUnit: TimeInterval {
3873
3974 /// Conversion of one day to a `TimeInterval`
4075 case days = 86400.0
41-
76+
4277 /// Conversion of one week to a `TimeInterval`
4378 case weeks = 604800.0
4479
0 commit comments