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

191 lines
7.4 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 extension Date {
// MARK: - Comparing Close
/// Decides whether a Date is "close by" another one passed in parameter,
/// where "Being close" is measured using a precision argument
/// which is initialized a 300 seconds, or 5 minutes.
///
/// - Parameters:
/// - refDate: reference date compare against to.
/// - precision: The precision of the comparison (default is 5 minutes, or 300 seconds).
/// - Returns: A boolean; true if close by, false otherwise.
func compareCloseTo(_ refDate: Date, precision: TimeInterval = 300) -> Bool {
return (abs(timeIntervalSince(refDate)) < precision)
}
// MARK: - Extendend Compare
/// Compare the date with the rule specified in the `compareType` parameter.
///
/// - Parameter compareType: comparison type.
/// - Returns: `true` if comparison succeded, `false` otherwise
func compare(_ compareType: DateComparisonType) -> Bool {
return inDefaultRegion().compare(compareType)
}
/// Returns a ComparisonResult value that indicates the ordering of two given dates based on
/// their components down to a given unit granularity.
///
/// - parameter date: date to compare.
/// - parameter granularity: The smallest unit that must, along with all larger units be less for the given dates
/// - returns: `ComparisonResult`
func compare(toDate refDate: Date, granularity: Calendar.Component) -> ComparisonResult {
return inDefaultRegion().compare(toDate: refDate.inDefaultRegion(), granularity: granularity)
}
/// Compares whether the receiver is before/before equal `date` based on their components down to a given unit granularity.
///
/// - Parameters:
/// - refDate: reference date
/// - orEqual: `true` to also check for equality
/// - granularity: smallest unit that must, along with all larger units, be less for the given dates
/// - Returns: Boolean
func isBeforeDate(_ refDate: Date, orEqual: Bool = false, granularity: Calendar.Component) -> Bool {
return inDefaultRegion().isBeforeDate(refDate.inDefaultRegion(), orEqual: orEqual, granularity: granularity)
}
/// Compares whether the receiver is after `date` based on their components down to a given unit granularity.
///
/// - Parameters:
/// - refDate: reference date
/// - orEqual: `true` to also check for equality
/// - granularity: Smallest unit that must, along with all larger units, be greater for the given dates.
/// - Returns: Boolean
func isAfterDate(_ refDate: Date, orEqual: Bool = false, granularity: Calendar.Component) -> Bool {
return inDefaultRegion().isAfterDate(refDate.inDefaultRegion(), orEqual: orEqual, granularity: granularity)
}
/// Return true if receiver date is contained in the range specified by two dates.
///
/// - Parameters:
/// - startDate: range upper bound date
/// - endDate: range lower bound date
/// - orEqual: `true` to also check for equality on date and date2
/// - granularity: smallest unit that must, along with all larger units, be greater for the given dates.
/// - Returns: Boolean
func isInRange(date startDate: Date, and endDate: Date, orEqual: Bool = false, granularity: Calendar.Component = .nanosecond) -> Bool {
return self.inDefaultRegion().isInRange(date: startDate.inDefaultRegion(), and: endDate.inDefaultRegion(), orEqual: orEqual, granularity: granularity)
}
/// Compares equality of two given dates based on their components down to a given unit
/// granularity.
///
/// - parameter date: date to compare
/// - parameter granularity: The smallest unit that must, along with all larger units, be equal for the given
/// dates to be considered the same.
///
/// - returns: `true` if the dates are the same down to the given granularity, otherwise `false`
func isInside(date: Date, granularity: Calendar.Component) -> Bool {
return (compare(toDate: date, granularity: granularity) == .orderedSame)
}
// MARK: - Date Earlier/Later
/// Return the earlier of two dates, between self and a given date.
///
/// - Parameter date: The date to compare to self
/// - Returns: The date that is earlier
func earlierDate(_ date: Date) -> Date {
return timeIntervalSince(date) <= 0 ? self : date
}
/// Return the later of two dates, between self and a given date.
///
/// - Parameter date: The date to compare to self
/// - Returns: The date that is later
func laterDate(_ date: Date) -> Date {
return timeIntervalSince(date) >= 0 ? self : date
}
}
extension Date {
/// Returns the difference in the calendar component given (like day, month or year)
/// with respect to the other date as a positive integer
public func difference(in component: Calendar.Component, from other: Date) -> Int? {
let (max, min) = orderDate(with: other)
let result = calendar.dateComponents([component], from: min, to: max)
return getValue(of: component, from: result)
}
/// Returns the differences in the calendar components given (like day, month and year)
/// with respect to the other date as dictionary with the calendar component as the key
/// and the diffrence as a positive integer as the value
public func differences(in components: Set<Calendar.Component>, from other: Date) -> [Calendar.Component: Int] {
let (max, min) = orderDate(with: other)
let differenceInDates = calendar.dateComponents(components, from: min, to: max)
var result = [Calendar.Component: Int]()
for component in components {
if let value = getValue(of: component, from: differenceInDates) {
result[component] = value
}
}
return result
}
private func getValue(of component: Calendar.Component, from dateComponents: DateComponents) -> Int? {
switch component {
case .era:
return dateComponents.era
case .year:
return dateComponents.year
case .month:
return dateComponents.month
case .day:
return dateComponents.day
case .hour:
return dateComponents.hour
case .minute:
return dateComponents.minute
case .second:
return dateComponents.second
case .weekday:
return dateComponents.weekday
case .weekdayOrdinal:
return dateComponents.weekdayOrdinal
case .quarter:
return dateComponents.quarter
case .weekOfMonth:
return dateComponents.weekOfMonth
case .weekOfYear:
return dateComponents.weekOfYear
case .yearForWeekOfYear:
return dateComponents.yearForWeekOfYear
case .nanosecond:
return dateComponents.nanosecond
case .calendar, .timeZone:
return nil
@unknown default:
assert(false, "unknown date component")
}
return nil
}
private func orderDate(with other: Date) -> (Date, Date) {
let first = self.timeIntervalSince1970
let second = other.timeIntervalSince1970
if first >= second {
return (self, other)
}
return (other, self)
}
}