// // SwiftDate // Parse, validate, manipulate, and display dates, time and timezones in Swift // // Created by Daniele Margutti // - Web: https://www.danielemargutti.com // - Twitter: https://twitter.com/danielemargutti // - Mail: hello@danielemargutti.com // // Copyright © 2019 Daniele Margutti. Licensed under MIT License. // import Foundation // MARK: - Weekday /// This define the weekdays for some functions. public enum WeekDay: Int { case sunday = 1, monday, tuesday, wednesday, thursday, friday, saturday /// Returns the name of the day given a specific locale. /// For example, for the `Friday` enum value, the en_AU locale would return "Friday" and fr_FR would return "samedi" /// /// - Parameter locale: locale of the output, omit to use the `defaultRegion`'s locale. /// - Returns: display name public func name(style: SymbolFormatStyle = .`default`, locale: LocaleConvertible = SwiftDate.defaultRegion.locale) -> String { let region = Region(calendar: SwiftDate.defaultRegion.calendar, zone: SwiftDate.defaultRegion.timeZone, locale: locale) let formatter = DateFormatter.sharedFormatter(forRegion: region, format: nil) let idx = (self.rawValue - 1) switch style { case .default: return formatter.weekdaySymbols[idx] case .defaultStandalone: return formatter.standaloneWeekdaySymbols[idx] case .short: return formatter.shortWeekdaySymbols[idx] case .standaloneShort: return formatter.shortStandaloneWeekdaySymbols[idx] case .veryShort: return formatter.veryShortWeekdaySymbols[idx] case .standaloneVeryShort: return formatter.veryShortStandaloneWeekdaySymbols[idx] } } /// Adds a number of days to the current weekday and returns the new weekday. /// /// - Parameter months: number of months to add /// - Returns: new month. public func add(days: Int) -> WeekDay { let normalized = days % 7 return WeekDay(rawValue: ((self.rawValue + normalized + 7 - 1) % 7) + 1)! } /// Subtracts a number of days from the current weekday and returns the new weekday. /// /// - Parameter months: number of days to subtract. May be negative, in which case it will be added /// - Returns: new weekday. public func subtract(days: Int) -> WeekDay { return add(days: -(days % 7)) } } // MARK: - Year public struct Year: CustomStringConvertible, Equatable { let year: Int public var description: String { return "\(self.year)" } /// Constructs a `Year` from the passed value. /// /// - Parameter year: year value. Can be negative. public init(_ year: Int) { self.year = year } /// Returns whether this year is a leap year /// /// - Returns: A boolean indicating whether this year is a leap year public func isLeap() -> Bool { return ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0) } /// Returns the number of days in this year /// /// - Returns: The number of days in this year public func numberOfDays() -> Int { return self.isLeap() ? 366 : 365 } } // MARK: - Month /// Defines months in a year public enum Month: Int, CustomStringConvertible, Equatable { case january = 0, february, march, april, may, june, july, august, september, october, november, december public var description: String { return self.name() } /// Returns the name of the month given a specific locale. /// For example, for the `January` enum value, the en_AU locale would return "January" and fr_FR would return "janvier" /// /// - Parameter locale: locale of the output, omit to use the `defaultRegion`'s locale. /// - Returns: display name public func name(style: SymbolFormatStyle = .`default`, locale: LocaleConvertible = SwiftDate.defaultRegion.locale) -> String { let region = Region(calendar: SwiftDate.defaultRegion.calendar, zone: SwiftDate.defaultRegion.timeZone, locale: locale) let formatter = DateFormatter.sharedFormatter(forRegion: region, format: nil) switch style { case .default: return formatter.monthSymbols[self.rawValue] case .defaultStandalone: return formatter.standaloneMonthSymbols[self.rawValue] case .short: return formatter.shortMonthSymbols[self.rawValue] case .standaloneShort: return formatter.shortStandaloneMonthSymbols[self.rawValue] case .veryShort: return formatter.veryShortMonthSymbols[self.rawValue] case .standaloneVeryShort: return formatter.veryShortStandaloneMonthSymbols[self.rawValue] } } /// Adds a number of months to the current month and returns the new month. /// /// - Parameter months: number of months to add /// - Returns: new month. public func add(months: Int) -> Month { let normalized = months % 12 return Month(rawValue: (self.rawValue + normalized + 12) % 12)! } /// Subtracts a number of months from the current month and returns the new month. /// /// - Parameter months: number of months to subtract. May be negative, in which case it will be added /// - Returns: new month. public func subtract(months: Int) -> Month { return add(months: -(months % 12)) } /// Returns the number of days in a this month for a given year /// /// - Parameter year: reference year. /// - Returns: The number of days in this month. public func numberOfDays(year: Int) -> Int { switch self { case .february: return Year(year).isLeap() ? 29 : 28 case .april, .june, .september, .november: return 30 default: return 31 } } }