Skip to content

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
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.