//
|
// 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 protocol DateToStringTrasformable {
|
static func format(_ date: DateRepresentable, options: Any?) -> String
|
}
|
|
public protocol StringToDateTransformable {
|
static func parse(_ string: String, region: Region?, options: Any?) -> DateInRegion?
|
}
|
|
// MARK: - Formatters
|
|
/// Format to represent a date to string
|
///
|
/// - iso: standard iso format. The ISO8601 formatted date, time and millisec "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
|
/// - extended: Extended format. "eee dd-MMM-yyyy GG HH:mm:ss.SSS zzz"
|
/// - rss: The RSS formatted date "EEE, d MMM yyyy HH:mm:ss ZZZ" i.e. "Fri, 09 Sep 2011 15:26:08 +0200"
|
/// - altRSS: The Alternative RSS formatted date "d MMM yyyy HH:mm:ss ZZZ" i.e. "09 Sep 2011 15:26:08 +0200"
|
/// - dotNet: The dotNet formatted date "/Date(%d%d)/" i.e. "/Date(1268123281843)/"
|
/// - httpHeader: The http header formatted date "EEE, dd MMM yyyy HH:mm:ss zzz" i.e. "Tue, 15 Nov 1994 12:45:26 GMT"
|
/// - custom: custom string format
|
/// - standard: A generic standard format date i.e. "EEE MMM dd HH:mm:ss Z yyyy"
|
/// - date: Date only format (short = "2/27/17", medium = "Feb 27, 2017", long = "February 27, 2017", full = "Monday, February 27, 2017"
|
/// - time: Time only format (short = "2:22 PM", medium = "2:22:06 PM", long = "2:22:06 PM EST", full = "2:22:06 PM Eastern Standard Time"
|
/// - dateTime: Date/Time format (short = "2/27/17, 2:22 PM", medium = "Feb 27, 2017, 2:22:06 PM", long = "February 27, 2017 at 2:22:06 PM EST", full = "Monday, February 27, 2017 at 2:22:06 PM Eastern Standard Time"
|
public enum DateToStringStyles {
|
case iso(_: ISOFormatter.Options)
|
case extended
|
case rss
|
case altRSS
|
case dotNet
|
case httpHeader
|
case sql
|
case date(_: DateFormatter.Style)
|
case time(_: DateFormatter.Style)
|
case dateTime(_: DateFormatter.Style)
|
case custom(_: String)
|
case standard
|
case relative(style: RelativeFormatter.Style?)
|
|
public func toString(_ date: DateRepresentable) -> String {
|
switch self {
|
case .iso(let opts): return ISOFormatter.format(date, options: opts)
|
case .extended: return date.formatterForRegion(format: DateFormats.extended).string(from: date.date)
|
case .rss: return date.formatterForRegion(format: DateFormats.rss).string(from: date.date)
|
case .altRSS: return date.formatterForRegion(format: DateFormats.altRSS).string(from: date.date)
|
case .sql: return date.formatterForRegion(format: DateFormats.sql).string(from: date.date)
|
case .dotNet: return DOTNETFormatter.format(date, options: nil)
|
case .httpHeader: return date.formatterForRegion(format: DateFormats.httpHeader).string(from: date.date)
|
case .custom(let format): return date.formatterForRegion(format: format).string(from: date.date)
|
case .standard: return date.formatterForRegion(format: DateFormats.standard).string(from: date.date)
|
case .date(let style):
|
return date.formatterForRegion(format: nil, configuration: {
|
$0.dateStyle = style
|
$0.timeStyle = .none
|
}).string(from: date.date)
|
case .time(let style):
|
return date.formatterForRegion(format: nil, configuration: {
|
$0.dateStyle = .none
|
$0.timeStyle = style
|
}).string(from: date.date)
|
case .dateTime(let style):
|
return date.formatterForRegion(format: nil, configuration: {
|
$0.dateStyle = style
|
$0.timeStyle = style
|
}).string(from: date.date)
|
case .relative(let style):
|
return RelativeFormatter.format(date, options: style)
|
}
|
}
|
|
}
|
|
// MARK: - Parsers
|
|
/// String to date transform
|
///
|
/// - iso: standard automatic iso parser (evaluate the date components automatically)
|
/// - extended: Extended format. "eee dd-MMM-yyyy GG HH:mm:ss.SSS zzz"
|
/// - rss: The RSS formatted date "EEE, d MMM yyyy HH:mm:ss ZZZ" i.e. "Fri, 09 Sep 2011 15:26:08 +0200"
|
/// - altRSS: The Alternative RSS formatted date "d MMM yyyy HH:mm:ss ZZZ" i.e. "09 Sep 2011 15:26:08 +0200"
|
/// - dotNet: The dotNet formatted date "/Date(%d%d)/" i.e. "/Date(1268123281843)/"
|
/// - httpHeader: The http header formatted date "EEE, dd MMM yyyy HH:mm:ss zzz" i.e. "Tue, 15 Nov 1994 12:45:26 GMT"
|
/// - strict: custom string format with lenient options active
|
/// - custom: custom string format
|
/// - standard: A generic standard format date i.e. "EEE MMM dd HH:mm:ss Z yyyy"
|
public enum StringToDateStyles {
|
case iso(_: ISOParser.Options)
|
case extended
|
case rss
|
case altRSS
|
case dotNet
|
case sql
|
case httpHeader
|
case strict(_: String)
|
case custom(_: String)
|
case standard
|
|
public func toDate(_ string: String, region: Region) -> DateInRegion? {
|
switch self {
|
case .iso(let options): return ISOParser.parse(string, region: region, options: options)
|
case .custom(let format): return DateInRegion(string, format: format, region: region)
|
case .extended: return DateInRegion(string, format: DateFormats.extended, region: region)
|
case .sql: return DateInRegion(string, format: DateFormats.sql, region: region)
|
case .rss: return DateInRegion(string, format: DateFormats.rss, region: Region.ISO)?.convertTo(locale: region.locale)
|
case .altRSS: return DateInRegion(string, format: DateFormats.altRSS, region: Region.ISO)?.convertTo(locale: region.locale)
|
case .dotNet: return DOTNETParser.parse(string, region: region, options: nil)
|
case .httpHeader: return DateInRegion(string, format: DateFormats.httpHeader, region: region)
|
case .standard: return DateInRegion(string, format: DateFormats.standard, region: region)
|
case .strict(let format):
|
let formatter = DateFormatter.sharedFormatter(forRegion: region, format: format)
|
formatter.isLenient = false
|
guard let absDate = formatter.date(from: string) else { return nil }
|
return DateInRegion(absDate, region: region)
|
}
|
}
|
}
|