add all api to sort by month
This commit is contained in:
286
Sources/App/Libraries/SwiftDate/Supports/Commons.swift
Normal file
286
Sources/App/Libraries/SwiftDate/Supports/Commons.swift
Normal file
@@ -0,0 +1,286 @@
|
||||
//
|
||||
// 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 extension DateFormatter {
|
||||
|
||||
/// Return the local thread shared formatter initialized with the configuration of the region passed.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - region: region used to pre-configure the cell.
|
||||
/// - format: optional format used to set the `dateFormat` property.
|
||||
/// - Returns: date formatter instance
|
||||
static func sharedFormatter(forRegion region: Region?, format: String? = nil) -> DateFormatter {
|
||||
let name = "SwiftDate_\(NSStringFromClass(DateFormatter.self))"
|
||||
let formatter: DateFormatter = threadSharedObject(key: name, create: { return DateFormatter() })
|
||||
if let region = region {
|
||||
formatter.timeZone = region.timeZone
|
||||
formatter.calendar = region.calendar
|
||||
formatter.locale = region.locale
|
||||
}
|
||||
formatter.dateFormat = (format ?? DateFormats.iso8601)
|
||||
return formatter
|
||||
}
|
||||
|
||||
/// Returned number formatter instance shared along calling thread to format ordinal numbers.
|
||||
///
|
||||
/// - Parameter locale: locale to set
|
||||
/// - Returns: number formatter instance
|
||||
@available(iOS 9.0, macOS 10.11, *)
|
||||
static func sharedOrdinalNumberFormatter(locale: LocaleConvertible) -> NumberFormatter {
|
||||
var formatter: NumberFormatter?
|
||||
let name = "SwiftDate_\(NSStringFromClass(NumberFormatter.self))"
|
||||
formatter = threadSharedObject(key: name, create: { return NumberFormatter() })
|
||||
formatter!.numberStyle = .ordinal
|
||||
formatter!.locale = locale.toLocale()
|
||||
return formatter!
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// This function create (if necessary) and return a thread singleton instance of the
|
||||
/// object you want.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - key: identifier of the object.
|
||||
/// - create: create routine used the first time you are about to create the object in thread.
|
||||
/// - Returns: instance of the object for caller's thread.
|
||||
internal func threadSharedObject<T: AnyObject>(key: String, create: () -> T) -> T {
|
||||
if let cachedObj = Thread.current.threadDictionary[key] as? T {
|
||||
return cachedObj
|
||||
} else {
|
||||
let newObject = create()
|
||||
Thread.current.threadDictionary[key] = newObject
|
||||
return newObject
|
||||
}
|
||||
}
|
||||
|
||||
/// Style used to format month, weekday, quarter symbols.
|
||||
/// Stand-alone properties are for use in places like calendar headers.
|
||||
/// Non-stand-alone properties are for use in context (for example, “Saturday, November 12th”).
|
||||
///
|
||||
/// - `default`: Default formatter (ie. `4th quarter` for quarter, `April` for months and `Wednesday` for weekdays)
|
||||
/// - defaultStandalone: See `default`; See `short`; stand-alone properties are for use in places like calendar headers.
|
||||
/// - short: Short symbols (ie. `Jun` for months, `Fri` for weekdays, `Q1` for quarters).
|
||||
/// - veryShort: Very short symbols (ie. `J` for months, `F` for weekdays, for quarter it just return `short` variant).
|
||||
/// - standaloneShort: See `short`; stand-alone properties are for use in places like calendar headers.
|
||||
/// - standaloneVeryShort: See `veryShort`; stand-alone properties are for use in places like calendar headers.
|
||||
public enum SymbolFormatStyle {
|
||||
case `default`
|
||||
case defaultStandalone
|
||||
case short
|
||||
case veryShort
|
||||
case standaloneShort
|
||||
case standaloneVeryShort
|
||||
}
|
||||
|
||||
/// Encapsulate the logic to use date format strings
|
||||
public struct DateFormats {
|
||||
|
||||
/// This is the built-in list of all supported formats for auto-parsing of a string to a date.
|
||||
internal static let builtInAutoFormat: [String] = [
|
||||
DateFormats.iso8601,
|
||||
"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'",
|
||||
"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSS'Z'",
|
||||
"yyyy-MM-dd'T'HH:mm:ss.SSSZ",
|
||||
"yyyy-MM-dd HH:mm:ss",
|
||||
"yyyy-MM-dd HH:mm",
|
||||
"yyyy-MM-dd",
|
||||
"h:mm:ss A",
|
||||
"h:mm A",
|
||||
"MM/dd/yyyy",
|
||||
"MMMM d, yyyy",
|
||||
"MMMM d, yyyy LT",
|
||||
"dddd, MMMM D, yyyy LT",
|
||||
"yyyyyy-MM-dd",
|
||||
"yyyy-MM-dd",
|
||||
"yyyy-'W'ww-E",
|
||||
"GGGG-'['W']'ww-E",
|
||||
"yyyy-'W'ww",
|
||||
"GGGG-'['W']'ww",
|
||||
"yyyy'W'ww",
|
||||
"yyyy-ddd",
|
||||
"HH:mm:ss.SSSS",
|
||||
"HH:mm:ss",
|
||||
"HH:mm",
|
||||
"HH"
|
||||
]
|
||||
|
||||
/// This is the ordered list of all formats SwiftDate can use in order to attempt parsing a passaed
|
||||
/// date expressed as string. Evaluation is made in order; you can add or remove new formats as you wish.
|
||||
/// In order to reset the list call `resetAutoFormats()` function.
|
||||
public static var autoFormats: [String] = DateFormats.builtInAutoFormat
|
||||
|
||||
/// Default ISO8601 format string
|
||||
public static let iso8601: String = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
|
||||
|
||||
/// Extended format
|
||||
public static let extended: String = "eee dd-MMM-yyyy GG HH:mm:ss.SSS zzz"
|
||||
|
||||
/// The Alternative RSS formatted date "d MMM yyyy HH:mm:ss ZZZ" i.e. "09 Sep 2011 15:26:08 +0200"
|
||||
public static let altRSS: String = "d MMM yyyy HH:mm:ss ZZZ"
|
||||
|
||||
/// The RSS formatted date "EEE, d MMM yyyy HH:mm:ss ZZZ" i.e. "Fri, 09 Sep 2011 15:26:08 +0200"
|
||||
public static let rss: String = "EEE, d MMM yyyy HH:mm:ss ZZZ"
|
||||
|
||||
/// The http header formatted date "EEE, dd MMM yyyy HH:mm:ss zzz" i.e. "Tue, 15 Nov 1994 12:45:26 GMT"
|
||||
public static let httpHeader: String = "EEE, dd MMM yyyy HH:mm:ss zzz"
|
||||
|
||||
/// A generic standard format date i.e. "EEE MMM dd HH:mm:ss Z yyyy"
|
||||
public static let standard: String = "EEE MMM dd HH:mm:ss Z yyyy"
|
||||
|
||||
/// SQL date format
|
||||
public static let sql: String = "yyyy-MM-dd'T'HH:mm:ss.SSSX"
|
||||
|
||||
/// Reset the list of auto formats to the initial settings.
|
||||
public static func resetAutoFormats() {
|
||||
autoFormats = DateFormats.builtInAutoFormat
|
||||
}
|
||||
|
||||
/// Parse a new string optionally passing the format in which is encoded. If no format is passed
|
||||
/// an attempt is made by cycling all the formats set in `autoFormats` property.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - string: date expressed as string.
|
||||
/// - suggestedFormat: optional format of the date expressed by the string (set it if you can in order to optimize the parse task).
|
||||
/// - region: region in which the date is expressed.
|
||||
/// - Returns: parsed absolute `Date`, `nil` if parse fails.
|
||||
public static func parse(string: String, format: String?, region: Region) -> Date? {
|
||||
let formats = (format != nil ? [format!] : DateFormats.autoFormats)
|
||||
return DateFormats.parse(string: string, formats: formats, region: region)
|
||||
}
|
||||
|
||||
public static func parse(string: String, formats: [String], region: Region) -> Date? {
|
||||
let formatter = DateFormatter.sharedFormatter(forRegion: region)
|
||||
|
||||
var parsedDate: Date?
|
||||
for format in formats {
|
||||
formatter.dateFormat = format
|
||||
formatter.locale = region.locale
|
||||
if let date = formatter.date(from: string) {
|
||||
parsedDate = date
|
||||
break
|
||||
}
|
||||
}
|
||||
return parsedDate
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Calendar Extension
|
||||
|
||||
public extension Calendar.Component {
|
||||
|
||||
internal static func toSet(_ src: [Calendar.Component]) -> Set<Calendar.Component> {
|
||||
var l: Set<Calendar.Component> = []
|
||||
src.forEach { l.insert($0) }
|
||||
return l
|
||||
}
|
||||
|
||||
internal var nsCalendarUnit: NSCalendar.Unit {
|
||||
switch self {
|
||||
case .era: return NSCalendar.Unit.era
|
||||
case .year: return NSCalendar.Unit.year
|
||||
case .month: return NSCalendar.Unit.month
|
||||
case .day: return NSCalendar.Unit.day
|
||||
case .hour: return NSCalendar.Unit.hour
|
||||
case .minute: return NSCalendar.Unit.minute
|
||||
case .second: return NSCalendar.Unit.second
|
||||
case .weekday: return NSCalendar.Unit.weekday
|
||||
case .weekdayOrdinal: return NSCalendar.Unit.weekdayOrdinal
|
||||
case .quarter: return NSCalendar.Unit.quarter
|
||||
case .weekOfMonth: return NSCalendar.Unit.weekOfMonth
|
||||
case .weekOfYear: return NSCalendar.Unit.weekOfYear
|
||||
case .yearForWeekOfYear: return NSCalendar.Unit.yearForWeekOfYear
|
||||
case .nanosecond: return NSCalendar.Unit.nanosecond
|
||||
case .calendar: return NSCalendar.Unit.calendar
|
||||
case .timeZone: return NSCalendar.Unit.timeZone
|
||||
@unknown default:
|
||||
fatalError("Unsupported type \(self)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Rounding mode for dates.
|
||||
/// Round off/up (ceil) or down (floor) target date.
|
||||
public enum RoundDateMode {
|
||||
case to5Mins
|
||||
case to10Mins
|
||||
case to30Mins
|
||||
case toMins(_: Int)
|
||||
case toCeil5Mins
|
||||
case toCeil10Mins
|
||||
case toCeil30Mins
|
||||
case toCeilMins(_: Int)
|
||||
case toFloor5Mins
|
||||
case toFloor10Mins
|
||||
case toFloor30Mins
|
||||
case toFloorMins(_: Int)
|
||||
}
|
||||
|
||||
/// Related type enum to get derivated date from a receiver date.
|
||||
public enum DateRelatedType {
|
||||
case startOfDay
|
||||
case endOfDay
|
||||
case startOfWeek
|
||||
case endOfWeek
|
||||
case startOfMonth
|
||||
case endOfMonth
|
||||
case tomorrow
|
||||
case tomorrowAtStart
|
||||
case yesterday
|
||||
case yesterdayAtStart
|
||||
case nearestMinute(minute:Int)
|
||||
case nearestHour(hour:Int)
|
||||
case nextWeekday(_: WeekDay)
|
||||
case nextDSTDate
|
||||
case prevMonth
|
||||
case nextMonth
|
||||
case prevWeek
|
||||
case nextWeek
|
||||
case nextYear
|
||||
case prevYear
|
||||
case nextDSTTransition
|
||||
}
|
||||
|
||||
public struct TimeCalculationOptions {
|
||||
|
||||
/// Specifies the technique the search algorithm uses to find result
|
||||
public var matchingPolicy: Calendar.MatchingPolicy
|
||||
|
||||
/// Specifies the behavior when multiple matches are found
|
||||
public var repeatedTimePolicy: Calendar.RepeatedTimePolicy
|
||||
|
||||
/// Specifies the direction in time to search
|
||||
public var direction: Calendar.SearchDirection
|
||||
|
||||
public init(matching: Calendar.MatchingPolicy = .nextTime,
|
||||
timePolicy: Calendar.RepeatedTimePolicy = .first,
|
||||
direction: Calendar.SearchDirection = .forward) {
|
||||
self.matchingPolicy = matching
|
||||
self.repeatedTimePolicy = timePolicy
|
||||
self.direction = direction
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - compactMap for Swift 4.0 (not necessary > 4.0)
|
||||
|
||||
#if swift(>=4.1)
|
||||
#else
|
||||
extension Collection {
|
||||
func compactMap<ElementOfResult>(
|
||||
_ transform: (Element) throws -> ElementOfResult?
|
||||
) rethrows -> [ElementOfResult] {
|
||||
return try flatMap(transform)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user