Files
cod-backend/Sources/App/Libraries/SwiftDate/DateInRegion/DateInRegion.swift
2020-06-14 21:46:44 -05:00

186 lines
7.2 KiB
Swift

//
// 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
public struct DateInRegion: DateRepresentable, Decodable, Encodable, CustomStringConvertible, Comparable, Hashable {
/// Absolute date represented. This date is not associated with any timezone or calendar
/// but represent the absolute number of seconds since Jan 1, 2001 at 00:00:00 UTC.
public internal(set) var date: Date
/// Associated region which define where the date is represented into the world.
public let region: Region
/// Formatter used to transform this object in a string. By default is `nil` because SwiftDate
/// uses the thread shared formatter in order to avoid expensive init of the `DateFormatter` object.
/// However, if you need of a custom behaviour you can set a valid value.
public var customFormatter: DateFormatter?
/// Extract date components by taking care of the region in which the date is expressed.
public var dateComponents: DateComponents {
return region.calendar.dateComponents(DateComponents.allComponentsSet, from: date)
}
/// Description of the date
public var description: String {
let absISODate = DateFormatter.sharedFormatter(forRegion: Region.UTC).string(from: date)
let representedDate = formatter(format: DateFormats.iso8601).string(from: date)
return "{abs_date='\(absISODate)', rep_date='\(representedDate)', region=\(region.description)"
}
/// The interval between the date value and 00:00:00 UTC on 1 January 1970.
public var timeIntervalSince1970: TimeInterval {
return date.timeIntervalSince1970
}
/// Initialize with an absolute date and represent it into given geographic region.
///
/// - Parameters:
/// - date: absolute date to represent.
/// - region: region in which the date is represented. If ignored `defaultRegion` is used instead.
public init(_ date: Date = Date(), region: Region = SwiftDate.defaultRegion) {
self.date = date
self.region = region
}
/// Initialize a new `DateInRegion` by parsing given string.
/// If you know the format of the string you should pass it in order to speed up the parsing process.
/// If you don't know the format leave it `nil` and parse is done between all formats in `DateFormats.builtInAutoFormats`
/// and the ordered list you can provide in `SwiftDate.autoParseFormats` (with attempt priority set on your list).
///
/// - Parameters:
/// - string: string with the date.
/// - format: format of the date.
/// - region: region in which the date is expressed.
public init?(_ string: String, format: String? = nil, region: Region = SwiftDate.defaultRegion) {
guard let date = DateFormats.parse(string: string,
format: format,
region: region) else {
return nil // failed to parse date
}
self.date = date
self.region = region
}
/// Initialize a new `DateInRegion` by parsing given string with the ordered list of passed formats.
/// If you know the format of the string you should pass it in order to speed up the parsing process.
/// If you don't know the format leave it `nil` and parse is done between all formats in `DateFormats.builtInAutoFormats`
/// and the ordered list you can provide in `SwiftDate.autoParseFormats` (with attempt priority set on your list).
///
/// - Parameters:
/// - string: string with the date.
/// - formats: ordered list of formats to use.
/// - region: region in which the date is expressed.
public init?(_ string: String, formats: [String]?, region: Region = SwiftDate.defaultRegion) {
guard let date = DateFormats.parse(string: string,
formats: (formats ?? SwiftDate.autoFormats),
region: region) else {
return nil // failed to parse date
}
self.date = date
self.region = region
}
/// Initialize a new date from the number of seconds passed since Unix Epoch.
///
/// - Parameters:
/// - interval: seconds since Unix Epoch.
/// - region: the region in which the date must be expressed, `nil` uses the default region at UTC timezone
public init(seconds interval: TimeInterval, region: Region = Region.UTC) {
self.date = Date(timeIntervalSince1970: interval)
self.region = region
}
/// Initialize a new date corresponding to the number of milliseconds since the Unix Epoch.
///
/// - Parameters:
/// - interval: seconds since the Unix Epoch timestamp.
/// - region: region in which the date must be expressed, `nil` uses the default region at UTC timezone
public init(milliseconds interval: Int, region: Region = Region.UTC) {
self.date = Date(timeIntervalSince1970: TimeInterval(interval) / 1000)
self.region = region
}
/// Initialize a new date with the opportunity to configure single date components via builder pattern.
/// Date is therfore expressed in passed region (`DateComponents`'s `timezone`,`calendar` and `locale` are ignored
/// and overwritten by the region if not `nil`).
///
/// - Parameters:
/// - configuration: configuration callback
/// - region: region in which the date is expressed.
/// Ignore to use `SwiftDate.defaultRegion`, `nil` to use `DateComponents` data.
public init?(components configuration: ((inout DateComponents) -> Void), region: Region? = SwiftDate.defaultRegion) {
var components = DateComponents()
configuration(&components)
let r = (region ?? Region(fromDateComponents: components))
guard let date = r.calendar.date(from: components) else {
return nil
}
self.date = date
self.region = r
}
/// Initialize a new date with given components.
///
/// - Parameters:
/// - components: components of the date.
/// - region: region in which the date is expressed.
/// Ignore to use `SwiftDate.defaultRegion`, `nil` to use `DateComponents` data.
public init?(components: DateComponents, region: Region?) {
let r = (region ?? Region(fromDateComponents: components))
guard let date = r.calendar.date(from: components) else {
return nil
}
self.date = date
self.region = r
}
/// Initialize a new date with given components.
public init(year: Int, month: Int, day: Int, hour: Int = 0, minute: Int = 0, second: Int = 0, nanosecond: Int = 0, region: Region = SwiftDate.defaultRegion) {
var components = DateComponents()
components.year = year
components.month = month
components.day = day
components.hour = hour
components.minute = minute
components.second = second
components.nanosecond = nanosecond
components.timeZone = region.timeZone
components.calendar = region.calendar
self.date = region.calendar.date(from: components)!
self.region = region
}
/// Return a date in the distant past.
///
/// - Returns: Date instance.
public static func past() -> DateInRegion {
return DateInRegion(Date.distantPast, region: SwiftDate.defaultRegion)
}
/// Return a date in the distant future.
///
/// - Returns: Date instance.
public static func future() -> DateInRegion {
return DateInRegion(Date.distantFuture, region: SwiftDate.defaultRegion)
}
// MARK: - Codable Support
enum CodingKeys: String, CodingKey {
case date
case region
}
}