diff --git a/Sources/HandySwift/Extensions/DateExt.swift b/Sources/HandySwift/Extensions/DateExt.swift index c454bef..a6a8ad8 100644 --- a/Sources/HandySwift/Extensions/DateExt.swift +++ b/Sources/HandySwift/Extensions/DateExt.swift @@ -1,7 +1,27 @@ import Foundation extension Date { - /// Returns a date offset by the specified time interval from this date to the past. + /// Creates a new Date by combining a ``GregorianDay`` with a ``GregorianTime``. + /// + /// This initializer allows you to create a Date instance from separate day and time components. + /// The resulting date will be in the specified timezone (defaulting to the current timezone). + /// + /// Example: + /// ```swift + /// let day = GregorianDay(year: 2024, month: 3, day: 21) + /// let time = GregorianTime(hour: 14, minute: 30) + /// let eventTime = Date(day: day, time: time) + /// ``` + /// + /// - Parameters: + /// - day: The GregorianDay representing the date components. + /// - time: The GregorianTime representing the time components. + /// - timeZone: The timezone to use for the date creation. Defaults to the current timezone. + public init(day: GregorianDay, time: GregorianTime, timeZone: TimeZone = .current) { + self = time.date(day: day, timeZone: timeZone) + } + + /// Returns a date offset by the specified time interval from this date to the past. /// This method is useful when you need to calculate a date that occurred a certain duration before the current date instance. /// For example, if you want to find out what the date was 2 hours ago from a given date, you can use this method by passing the time interval for 2 hours in seconds. /// diff --git a/Sources/HandySwift/HandySwift.docc/Essentials/New Types.md b/Sources/HandySwift/HandySwift.docc/Essentials/New Types.md index 5e5dbfd..b70bbaf 100644 --- a/Sources/HandySwift/HandySwift.docc/Essentials/New Types.md +++ b/Sources/HandySwift/HandySwift.docc/Essentials/New Types.md @@ -47,11 +47,11 @@ let todayNextWeek = GregorianDay.today.advanced(by: 7) > Note: `GregorianDay` conforms to all the protocols you would expect, such as `Codable`, `Hashable`, and `Comparable`. For encoding/decoding, it uses the ISO format as in "2014-07-13". -``GregorianTimeOfDay`` is the counterpart: +``GregorianTime`` is the counterpart: ```swift -let iPhoneAnnounceTime = GregorianTimeOfDay(hour: 09, minute: 41) -let anHourFromNow = GregorianTimeOfDay.now.advanced(by: .hours(1)) +let iPhoneAnnounceTime = GregorianTime(hour: 09, minute: 41) +let anHourFromNow = GregorianTime.now.advanced(by: .hours(1)) let date = iPhoneAnnounceTime.date(day: GregorianDay.today) // => Date ``` @@ -120,7 +120,7 @@ Note that the ``Debouncer`` was stored in a property so ``Debouncer/cancelAll()` ### Date & Time - ``GregorianDay`` -- ``GregorianTimeOfDay`` +- ``GregorianTime`` ### UI Helpers diff --git a/Sources/HandySwift/Types/GregorianDay.swift b/Sources/HandySwift/Types/GregorianDay.swift index c61cceb..f238d5e 100644 --- a/Sources/HandySwift/Types/GregorianDay.swift +++ b/Sources/HandySwift/Types/GregorianDay.swift @@ -218,6 +218,21 @@ public struct GregorianDay { ) return components.date! } + + /// Returns a `Date` representing this day at the specified time. + /// + /// - Parameters: + /// - timeOfDay: The time of day to set for the resulting date. + /// - timeZone: The time zone for which to calculate the date. Defaults to the users current timezone. + /// - Returns: A `Date` representing this day at the specified time. + /// + /// Example: + /// ```swift + /// let noonToday = GregorianDay.today.date(timeOfDay: .noon) // today at 12:00 + /// ``` + public func date(timeOfDay: GregorianTime, timeZone: TimeZone = .current) -> Date { + timeOfDay.date(day: self, timeZone: timeZone) + } } extension GregorianDay: Codable { diff --git a/Sources/HandySwift/Types/GregorianTimeOfDay.swift b/Sources/HandySwift/Types/GregorianTime.swift similarity index 67% rename from Sources/HandySwift/Types/GregorianTimeOfDay.swift rename to Sources/HandySwift/Types/GregorianTime.swift index 289341d..2106d08 100644 --- a/Sources/HandySwift/Types/GregorianTimeOfDay.swift +++ b/Sources/HandySwift/Types/GregorianTime.swift @@ -2,13 +2,13 @@ import Foundation /// A time without date info. /// -/// `GregorianTimeOfDay` represents a time of day without any associated date information. It provides functionalities to work with time components like hour, minute, and second, and perform operations such as initializing from a given date, calculating durations, advancing, and reversing time. +/// `GregorianTime` represents a time of day without any associated date information. It provides functionalities to work with time components like hour, minute, and second, and perform operations such as initializing from a given date, calculating durations, advancing, and reversing time. /// /// Example: /// ```swift /// // Initializing from a given date /// let date = Date() -/// let timeOfDay = GregorianTimeOfDay(date: date) +/// let timeOfDay = GregorianTime(date: date) /// /// // Calculating duration since the start of the day /// let durationSinceStartOfDay: Duration = timeOfDay.durationSinceStartOfDay @@ -20,7 +20,7 @@ import Foundation /// // Reversing time by a duration /// let reversedTime = timeOfDay.reversed(by: .minutes(15)) /// ``` -public struct GregorianTimeOfDay { +public struct GregorianTime { /// The number of days beyond the current day. public var overflowingDays: Int /// The hour component of the time. @@ -30,7 +30,7 @@ public struct GregorianTimeOfDay { /// The second component of the time. public var second: Int - /// Initializes a `GregorianTimeOfDay` instance from a given date. + /// Initializes a `GregorianTime` instance from a given date. /// /// - Parameter date: The date from which to extract time components. public init(date: Date) { @@ -41,7 +41,7 @@ public struct GregorianTimeOfDay { self.second = components.second! } - /// Initializes a `GregorianTimeOfDay` instance with the provided time components. + /// Initializes a `GregorianTime` instance with the provided time components. /// /// - Parameters: /// - hour: The hour component. @@ -64,7 +64,7 @@ public struct GregorianTimeOfDay { /// - day: The day to which the time belongs. /// - timeZone: The time zone to use for the conversion (default is the current time zone). /// - Returns: A `Date` object representing the time. - public func date(day: GregorianDay, timeZone: TimeZone = Calendar.current.timeZone) -> Date { + public func date(day: GregorianDay, timeZone: TimeZone = .current) -> Date { let components = DateComponents( calendar: Calendar(identifier: .gregorian), timeZone: timeZone, @@ -78,7 +78,7 @@ public struct GregorianTimeOfDay { return components.date!.addingTimeInterval(.days(Double(self.overflowingDays))) } - /// Initializes a `GregorianTimeOfDay` instance from the duration since the start of the day. + /// Initializes a `GregorianTime` instance from the duration since the start of the day. /// /// - Parameter durationSinceStartOfDay: The duration since the start of the day. @available(iOS 16, macOS 13, tvOS 16, visionOS 1, watchOS 9, *) @@ -98,36 +98,36 @@ public struct GregorianTimeOfDay { /// Advances the time by the specified duration. /// /// - Parameter duration: The duration by which to advance the time. - /// - Returns: A new `GregorianTimeOfDay` instance advanced by the specified duration. + /// - Returns: A new `GregorianTime` instance advanced by the specified duration. @available(iOS 16, macOS 13, tvOS 16, visionOS 1, watchOS 9, *) public func advanced(by duration: Duration) -> Self { - GregorianTimeOfDay(durationSinceStartOfDay: self.durationSinceStartOfDay + duration) + GregorianTime(durationSinceStartOfDay: self.durationSinceStartOfDay + duration) } /// Reverses the time by the specified duration. /// /// - Parameter duration: The duration by which to reverse the time. - /// - Returns: A new `GregorianTimeOfDay` instance reversed by the specified duration. + /// - Returns: A new `GregorianTime` instance reversed by the specified duration. @available(iOS 16, macOS 13, tvOS 16, visionOS 1, watchOS 9, *) public func reversed(by duration: Duration) -> Self { - GregorianTimeOfDay(durationSinceStartOfDay: self.durationSinceStartOfDay - duration) + GregorianTime(durationSinceStartOfDay: self.durationSinceStartOfDay - duration) } } -extension GregorianTimeOfDay: Codable, Hashable, Sendable {} -extension GregorianTimeOfDay: Identifiable { +extension GregorianTime: Codable, Hashable, Sendable {} +extension GregorianTime: Identifiable { /// The unique identifier of the time, formatted as "hour:minute:second". public var id: String { "\(self.hour):\(self.minute):\(self.second)" } } -extension GregorianTimeOfDay: Comparable { - /// Compares two `GregorianTimeOfDay` instances. +extension GregorianTime: Comparable { + /// Compares two `GregorianTime` instances. /// /// - Parameters: /// - left: The left-hand side of the comparison. /// - right: The right-hand side of the comparison. /// - Returns: `true` if the left time is less than the right time; otherwise, `false`. - public static func < (left: GregorianTimeOfDay, right: GregorianTimeOfDay) -> Bool { + public static func < (left: GregorianTime, right: GregorianTime) -> Bool { guard left.overflowingDays == right.overflowingDays else { return left.overflowingDays < right.overflowingDays } guard left.hour == right.hour else { return left.hour < right.hour } guard left.minute == right.minute else { return left.minute < right.minute } @@ -135,11 +135,28 @@ extension GregorianTimeOfDay: Comparable { } } -extension GregorianTimeOfDay { +extension GregorianTime { /// The zero time of day (00:00:00). - public static var zero: Self { GregorianTimeOfDay(hour: 0, minute: 0, second: 0) } + public static var zero: Self { GregorianTime(hour: 0, minute: 0, second: 0) } /// The current time of day. - public static var now: Self { GregorianTimeOfDay(date: Date()) } + public static var now: Self { GregorianTime(date: Date()) } + /// Noon (12:00:00). + public static var noon: Self { GregorianTime(hour: 12, minute: 0, second: 0) } } -extension GregorianTimeOfDay: Withable {} +extension GregorianTime: Withable {} + +/// Provides backward compatibility for the renamed `GregorianTime` type. +/// +/// This type has been renamed to ``GregorianTime`` to better reflect its purpose and maintain consistency with other types in the framework. +/// +/// Instead of using `GregorianTimeOfDay`, use ``GregorianTime``: +/// ```swift +/// // Old code: +/// let time = GregorianTimeOfDay(hour: 14, minute: 30) +/// +/// // New code: +/// let time = GregorianTime(hour: 14, minute: 30) +/// ``` +@available(*, deprecated, renamed: "GregorianTime", message: "Use GregorianTime instead. This type has been renamed for better clarity and consistency.") +public typealias GregorianTimeOfDay = GregorianTime