|
|
|
//
|
|
|
|
// TimeChunk.swift
|
|
|
|
// DateTools
|
|
|
|
//
|
|
|
|
// Created by Grayson Webster on 8/19/16.
|
|
|
|
// Copyright © 2016 Grayson Webster. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
|
|
|
|
/**
|
|
|
|
* TimeChunk represents an abstract collection of `DateComponent`s intended for use in date manipulation. A `TimeChunk` differs from a
|
|
|
|
* TimeInterval in that the former depends on the `Calendar` class (and takes into account daylight savings, leap year, etc.) while the
|
|
|
|
* latter depends on hard, second based adjustments that are independent from calendar constructs.
|
|
|
|
*
|
|
|
|
* In essence, TimeChunk is meant to be a thin, more flexible layer over the `Calender` and `DateComponent` classes for ease of use.
|
|
|
|
* `TimeChunk`s may be created either by calling the provided initializer or shorthand like `2.days`. TimeChunks are manipulable and combine
|
|
|
|
* using basic arithmetic operators like + and -.
|
|
|
|
*
|
|
|
|
* For more information about the utility of TimeChunks in relation to Dates, see the `Date+Manipulations` class.
|
|
|
|
*/
|
|
|
|
public struct TimeChunk {
|
|
|
|
// MARK: - Variables
|
|
|
|
|
|
|
|
public var seconds = 0
|
|
|
|
public var minutes = 0
|
|
|
|
public var hours = 0
|
|
|
|
public var days = 0
|
|
|
|
public var weeks = 0
|
|
|
|
public var months = 0
|
|
|
|
public var years = 0
|
|
|
|
|
|
|
|
public init() {}
|
|
|
|
|
|
|
|
public init(seconds: Int, minutes: Int, hours: Int, days: Int, weeks: Int, months: Int, years: Int) {
|
|
|
|
self.seconds = seconds
|
|
|
|
self.minutes = minutes
|
|
|
|
self.hours = hours
|
|
|
|
self.days = days
|
|
|
|
self.weeks = weeks
|
|
|
|
self.months = months
|
|
|
|
self.years = years
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: - Comparisons
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if two `TimeChunk`s are equal.
|
|
|
|
*
|
|
|
|
* - parameter chunk: `TimeChunk` to compare with self
|
|
|
|
*
|
|
|
|
* - returns: If all components in both `TimeChunk`s are equal
|
|
|
|
*/
|
|
|
|
public func equals(chunk: TimeChunk) -> Bool {
|
|
|
|
return (seconds == chunk.seconds && minutes == chunk.minutes && hours == chunk.hours && days == chunk.days && weeks == chunk.weeks && months == chunk.months && years == chunk.years)
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: - Conversion
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generic conversion method. Years are taken to mean
|
|
|
|
* 365 days. This method should not be used for accurate
|
|
|
|
* date operations. Ex. 456.days.to(.years) will return 1.
|
|
|
|
*
|
|
|
|
* ! Months are not supported for conversions. They are not a
|
|
|
|
* well defined unit of time without the context of a calendar. !
|
|
|
|
*/
|
|
|
|
public func to(_ unit: TimeUnits) -> Int {
|
|
|
|
if months != 0 {
|
|
|
|
Logger.info("Months are not supported for conversion due to their uncertain number of days.")
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
if unit == .seconds {
|
|
|
|
var total = seconds
|
|
|
|
total += minutes * 60
|
|
|
|
total += hours * 60 * 60
|
|
|
|
total += days * 24 * 60 * 60
|
|
|
|
total += weeks * 7 * 24 * 60 * 60
|
|
|
|
total += years * 365 * 24 * 60 * 60
|
|
|
|
return total
|
|
|
|
} else if unit == .minutes {
|
|
|
|
var total = minutes
|
|
|
|
total += seconds / 60
|
|
|
|
total += hours * 60
|
|
|
|
total += days * 24 * 60
|
|
|
|
total += weeks * 7 * 24 * 60
|
|
|
|
total += years * 365 * 24 * 60
|
|
|
|
return total
|
|
|
|
} else if unit == .hours {
|
|
|
|
var total = hours
|
|
|
|
let secondsToMinutes = seconds / 60
|
|
|
|
total += (minutes + secondsToMinutes) / 60
|
|
|
|
total += days * 24
|
|
|
|
total += weeks * 7 * 24
|
|
|
|
total += years * 365 * 24
|
|
|
|
return total
|
|
|
|
} else if unit == .days {
|
|
|
|
var total = days
|
|
|
|
let secondsToMinutes = seconds / 60
|
|
|
|
let minutesToHours = (minutes + secondsToMinutes) / 60
|
|
|
|
total += (hours + minutesToHours) / 24
|
|
|
|
total += weeks * 7
|
|
|
|
total += years * 365
|
|
|
|
return total
|
|
|
|
} else if unit == .weeks {
|
|
|
|
var total = weeks
|
|
|
|
let secondsToMinutes = seconds / 60
|
|
|
|
let minutesToHours = (minutes + secondsToMinutes) / 60
|
|
|
|
let hoursToDays = (hours + minutesToHours) / 24
|
|
|
|
total += (days + hoursToDays) / 7
|
|
|
|
total += years * 52
|
|
|
|
return total
|
|
|
|
} else if unit == .years {
|
|
|
|
var total = years
|
|
|
|
let secondsToMinutes = seconds / 60
|
|
|
|
let minutesToHours = (minutes + secondsToMinutes) / 60
|
|
|
|
let hoursToDays = (hours + minutesToHours) / 24
|
|
|
|
let weeksToDays = weeks * 7
|
|
|
|
total += (days + hoursToDays + weeksToDays) / 365
|
|
|
|
return total
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: - Date Creation
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the current date decreased by the amount in self
|
|
|
|
*/
|
|
|
|
public var earlier: Date {
|
|
|
|
return earlier(than: Date())
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the current date increased by the amount in self
|
|
|
|
*/
|
|
|
|
public var later: Date {
|
|
|
|
return later(than: Date())
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the given date decreased by the amount in self.
|
|
|
|
*
|
|
|
|
* - parameter date: The date to decrease
|
|
|
|
*
|
|
|
|
* - returns: A new date with components decreased according to the variables of self
|
|
|
|
*/
|
|
|
|
public func earlier(than date: Date) -> Date {
|
|
|
|
return date.subtract(self)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the given date increased by the amount in self.
|
|
|
|
*
|
|
|
|
* - parameter date: The date to increase
|
|
|
|
*
|
|
|
|
* - returns: A new date with components increased according to the variables of self
|
|
|
|
*/
|
|
|
|
public func later(than date: Date) -> Date {
|
|
|
|
return date.add(self)
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: - Lengthen / Shorten
|
|
|
|
|
|
|
|
// MARK: In Place
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Increase the variables of self (`TimeChunk`) by the variables of the given `TimeChunk`.
|
|
|
|
*
|
|
|
|
* - parameter chunk: The `TimeChunk` to increase self by
|
|
|
|
*
|
|
|
|
* - returns: The `TimeChunk` with variables increased
|
|
|
|
*/
|
|
|
|
public func lengthened(by chunk: TimeChunk) -> TimeChunk {
|
|
|
|
var newChunk = TimeChunk()
|
|
|
|
newChunk.seconds = seconds + chunk.seconds
|
|
|
|
newChunk.minutes = minutes + chunk.minutes
|
|
|
|
newChunk.hours = hours + chunk.hours
|
|
|
|
newChunk.days = days + chunk.days
|
|
|
|
newChunk.weeks = weeks + chunk.weeks
|
|
|
|
newChunk.months = months + chunk.months
|
|
|
|
newChunk.years = years + chunk.years
|
|
|
|
|
|
|
|
return newChunk
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Decrease the variables of self (`TimeChunk`) by the variables of the given `TimeChunk`.
|
|
|
|
*
|
|
|
|
* - parameter chunk: The `TimeChunk` to decrease self by
|
|
|
|
*
|
|
|
|
* - returns: The `TimeChunk` with variables decreased
|
|
|
|
*/
|
|
|
|
public func shortened(by chunk: TimeChunk) -> TimeChunk {
|
|
|
|
var newChunk = TimeChunk()
|
|
|
|
newChunk.seconds = seconds - chunk.seconds
|
|
|
|
newChunk.minutes = minutes - chunk.minutes
|
|
|
|
newChunk.hours = hours - chunk.hours
|
|
|
|
newChunk.days = days - chunk.days
|
|
|
|
newChunk.weeks = weeks - chunk.weeks
|
|
|
|
newChunk.months = months - chunk.months
|
|
|
|
newChunk.years = years - chunk.years
|
|
|
|
|
|
|
|
return newChunk
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: Mutation
|
|
|
|
|
|
|
|
/**
|
|
|
|
* In place, increase the variables of self (`TimeChunk`) by the variables of the given `TimeChunk`.
|
|
|
|
*
|
|
|
|
* - parameter chunk: The `TimeChunk` to increase self by
|
|
|
|
*/
|
|
|
|
public mutating func lengthen(by chunk: TimeChunk) {
|
|
|
|
seconds += chunk.seconds
|
|
|
|
minutes += chunk.minutes
|
|
|
|
hours += chunk.hours
|
|
|
|
days += chunk.days
|
|
|
|
weeks += chunk.weeks
|
|
|
|
months += chunk.months
|
|
|
|
years += chunk.years
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* In place, decrease the variables of self (`TimeChunk`) by the variables of the given `TimeChunk`.
|
|
|
|
*
|
|
|
|
* - parameter chunk: The `TimeChunk` to decrease self by
|
|
|
|
*/
|
|
|
|
public mutating func shorten(by chunk: TimeChunk) {
|
|
|
|
seconds -= chunk.seconds
|
|
|
|
minutes -= chunk.minutes
|
|
|
|
hours -= chunk.hours
|
|
|
|
days -= chunk.days
|
|
|
|
weeks -= chunk.weeks
|
|
|
|
months -= chunk.months
|
|
|
|
years -= chunk.years
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: - Operator Overloads
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Operator overload for adding two `TimeChunk`s
|
|
|
|
*/
|
|
|
|
public static func + (leftAddend: TimeChunk, rightAddend: TimeChunk) -> TimeChunk {
|
|
|
|
return leftAddend.lengthened(by: rightAddend)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Operator overload for subtracting two `TimeChunk`s
|
|
|
|
*/
|
|
|
|
public static func - (minuend: TimeChunk, subtrahend: TimeChunk) -> TimeChunk {
|
|
|
|
return minuend.shortened(by: subtrahend)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Operator overload for checking if two `TimeChunk`s are equal
|
|
|
|
*/
|
|
|
|
public static func == (left: TimeChunk, right: TimeChunk) -> Bool {
|
|
|
|
return left.equals(chunk: right)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Operator overload for inverting (negating all variables) a `TimeChunk`
|
|
|
|
*/
|
|
|
|
public static prefix func - (chunk: TimeChunk) -> TimeChunk {
|
|
|
|
var invertedChunk = chunk
|
|
|
|
invertedChunk.seconds = -chunk.seconds
|
|
|
|
invertedChunk.minutes = -chunk.minutes
|
|
|
|
invertedChunk.hours = -chunk.hours
|
|
|
|
invertedChunk.days = -chunk.days
|
|
|
|
invertedChunk.weeks = -chunk.weeks
|
|
|
|
invertedChunk.months = -chunk.months
|
|
|
|
invertedChunk.years = -chunk.years
|
|
|
|
return invertedChunk
|
|
|
|
}
|
|
|
|
}
|