Instantly share code, notes, and snippets.

Embed
What would you like to do?
extension Date: Strideable {
func distance(to other: Date) -> DateStride {
// ...
}
func advanced(by n: DateStride) -> Date {
switch n {
case .year(let value), .month(let value), .day(let value):
return Calendar.current.date(byAdding: n.component, value: value, to: self)!
}
}
}
enum DateStride {
case year(Int)
case month(Int)
case day(Int)
var component: Calendar.Component {
switch self {
case .year(_):
return .year
case .month(_):
return .month
case .day(_):
return .day
}
}
}
extension DateStride: SignedNumber {
prefix static func -(x: DateStride) -> DateStride {
switch x {
case .year(let value):
return .year(-value)
case .month(let value):
return .month(-value)
case .day(let value):
return .day(-value)
}
}
static func -(lhs: DateStride, rhs: DateStride) -> DateStride {
switch (lhs, rhs) {
case (.year(let lhsValue), .year(let rhsValue)):
return .year(lhsValue - rhsValue)
case (.month(let lhsValue), .month(let rhsValue)):
return .month(lhsValue - rhsValue)
case (.day(let lhsValue), .day(let rhsValue)):
return .day(lhsValue - rhsValue)
default:
fatalError("Operation not permitted")
}
}
}
// MARK: - ExpressibleByIntegerLiteral
extension DateStride {
init(integerLiteral value: Int) {
self = .day(value)
}
}
// MARK: - Comparable
extension DateStride {
static func <(lhs: DateStride, rhs: DateStride) -> Bool {
switch (lhs, rhs) {
case (.year(let lhsValue), .year(let rhsValue)):
return lhsValue < rhsValue
case (.month(let lhsValue), .month(let rhsValue)):
return lhsValue < rhsValue
case (.day(let lhsValue), .day(let rhsValue)):
return lhsValue < rhsValue
default:
return false
}
}
static func ==(lhs: DateStride, rhs: DateStride) -> Bool {
switch (lhs, rhs) {
case (.year(let lhsValue), .year(let rhsValue)):
return lhsValue == rhsValue
case (.month(let lhsValue), .month(let rhsValue)):
return lhsValue == rhsValue
case (.day(let lhsValue), .day(let rhsValue)):
return lhsValue == rhsValue
default:
return false
}
}
static func <=(lhs: DateStride, rhs: DateStride) -> Bool {
return lhs < rhs || lhs == rhs
}
static func >=(lhs: DateStride, rhs: DateStride) -> Bool {
return !(lhs < rhs)
}
static func >(lhs: DateStride, rhs: DateStride) -> Bool {
return !(lhs <= rhs)
}
}
import UIKit
// MARK: - Offsets and distances
extension Date {
func distance(between otherDate: Date, unit: Calendar.Component) -> Int {
let reducedSelf = reduced(to: unit)
let reducedOther = otherDate.reduced(to: unit)
return Calendar.current.dateComponents([unit], from: reducedSelf, to: reducedOther).value(for: unit) ?? 0
}
func advanced(by value: Int, unit: Calendar.Component) -> Date {
return (value == 0 ? self : Calendar.current.date(byAdding: unit, value: value, to: self)!).reduced(to: unit)
}
private func reduced(to component: Calendar.Component) -> Date {
let components: [Calendar.Component] = [.era, .year, .month, .day, .hour, .minute, .second]
guard let index = components.index(of: component) else {
return self
}
let componentSet = Set(components[0 ... index])
let calendar = Calendar.current
return calendar.date(from: calendar.dateComponents(componentSet, from: self)) ?? self
}
}
// MARK: - Strideable
extension Date: Strideable {
public func distance(to other: Date) -> DateStride {
print("Diat")
let selfComponents = Calendar.current.dateComponents([.year, .month, .day], from: self)
let otherComponents = Calendar.current.dateComponents([.year, .month, .day], from: other)
if selfComponents.year != otherComponents.year {
return .year(distance(between: other, unit: .year))
}
if selfComponents.month != otherComponents.month {
return .month(distance(between: other, unit: .month))
}
return .day(distance(between: other, unit: .day))
}
public func advanced(by n: DateStride) -> Date {
switch n {
case .year(let value), .month(let value), .day(let value):
return Calendar.current.date(byAdding: n.component, value: value, to: self)!
}
}
}
public enum DateStride {
case year(Int)
case month(Int)
case day(Int)
var component: Calendar.Component {
switch self {
case .year(_): return .year
case .month(_): return .month
case .day(_): return .day
}
}
}
extension DateStride: SignedNumber {
prefix public static func -(x: DateStride) -> DateStride {
switch x {
case .year(let value): return .year(-value)
case .month(let value): return .month(-value)
case .day(let value): return .day(-value)
}
}
public static func -(lhs: DateStride, rhs: DateStride) -> DateStride {
switch (lhs, rhs) {
case (.year(let lhsValue), .year(let rhsValue)):
return .year(lhsValue - rhsValue)
case (.month(let lhsValue), .month(let rhsValue)):
return .month(lhsValue - rhsValue)
case (.day(let lhsValue), .day(let rhsValue)):
return .day(lhsValue - rhsValue)
default:
fatalError("Operation not permitted")
}
}
}
// MARK: - ExpressibleByIntegerLiteral
public extension DateStride {
public init(integerLiteral value: Int) {
self = .day(value)
}
}
// MARK: - Comparable
public extension DateStride {
public static func <(lhs: DateStride, rhs: DateStride) -> Bool {
switch (lhs, rhs) {
case (.year(let lhsValue), .year(let rhsValue)):
return lhsValue < rhsValue
case (.month(let lhsValue), .month(let rhsValue)):
return lhsValue < rhsValue
case (.day(let lhsValue), .day(let rhsValue)):
return lhsValue < rhsValue
default:
return false
}
}
public static func ==(lhs: DateStride, rhs: DateStride) -> Bool {
switch (lhs, rhs) {
case (.year(let lhsValue), .year(let rhsValue)):
return lhsValue == rhsValue
case (.month(let lhsValue), .month(let rhsValue)):
return lhsValue == rhsValue
case (.day(let lhsValue), .day(let rhsValue)):
return lhsValue == rhsValue
default:
return false
}
}
public static func <=(lhs: DateStride, rhs: DateStride) -> Bool {
return lhs < rhs || lhs == rhs
}
public static func >=(lhs: DateStride, rhs: DateStride) -> Bool {
return !(lhs < rhs)
}
public static func >(lhs: DateStride, rhs: DateStride) -> Bool {
return !(lhs <= rhs)
}
}
stride(from: Date(), to: Date().addingTimeInterval(100_000_000), by: .month(3)).forEach { print($0) }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment