diff --git a/Clocker/Clocker.xcodeproj/project.pbxproj b/Clocker/Clocker.xcodeproj/project.pbxproj index 1b886cc..0a8668a 100755 --- a/Clocker/Clocker.xcodeproj/project.pbxproj +++ b/Clocker/Clocker.xcodeproj/project.pbxproj @@ -71,11 +71,8 @@ 35C36EF822595F14002FA5C6 /* Onboarding.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 35C36EEF22595F14002FA5C6 /* Onboarding.storyboard */; }; 35C36EF922595F14002FA5C6 /* OnboardingParentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36EF022595F14002FA5C6 /* OnboardingParentViewController.swift */; }; 35C36EFB2259616B002FA5C6 /* Solar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36EFA2259616B002FA5C6 /* Solar.swift */; }; - 35C36F0D225961DA002FA5C6 /* TimePeriod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36EFD225961D9002FA5C6 /* TimePeriod.swift */; }; 35C36F0E225961DA002FA5C6 /* Date+Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36EFE225961D9002FA5C6 /* Date+Bundle.swift */; }; - 35C36F0F225961DA002FA5C6 /* TimePeriodCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36EFF225961D9002FA5C6 /* TimePeriodCollection.swift */; }; 35C36F10225961DA002FA5C6 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36F00225961D9002FA5C6 /* Constants.swift */; }; - 35C36F11225961DA002FA5C6 /* TimePeriodGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36F01225961D9002FA5C6 /* TimePeriodGroup.swift */; }; 35C36F12225961DA002FA5C6 /* Date+Components.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36F02225961DA002FA5C6 /* Date+Components.swift */; }; 35C36F13225961DA002FA5C6 /* Date+TimeAgo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36F03225961DA002FA5C6 /* Date+TimeAgo.swift */; }; 35C36F14225961DA002FA5C6 /* Integer+DateTools.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36F04225961DA002FA5C6 /* Integer+DateTools.swift */; }; @@ -86,7 +83,6 @@ 35C36F19225961DA002FA5C6 /* Enums.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36F09225961DA002FA5C6 /* Enums.swift */; }; 35C36F1A225961DA002FA5C6 /* Date+Manipulations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36F0A225961DA002FA5C6 /* Date+Manipulations.swift */; }; 35C36F1B225961DA002FA5C6 /* Date+Format.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36F0B225961DA002FA5C6 /* Date+Format.swift */; }; - 35C36F1C225961DA002FA5C6 /* TimePeriodChain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36F0C225961DA002FA5C6 /* TimePeriodChain.swift */; }; 35C36F2022596253002FA5C6 /* OneWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36F1E22596253002FA5C6 /* OneWindowController.swift */; }; 35C36F2122596253002FA5C6 /* AppearanceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36F1F22596253002FA5C6 /* AppearanceViewController.swift */; }; 35C36F2B2259D6FA002FA5C6 /* ParentPanelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36F272259D6FA002FA5C6 /* ParentPanelController.swift */; }; @@ -313,11 +309,8 @@ 35C36EEF22595F14002FA5C6 /* Onboarding.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Onboarding.storyboard; sourceTree = ""; }; 35C36EF022595F14002FA5C6 /* OnboardingParentViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingParentViewController.swift; sourceTree = ""; }; 35C36EFA2259616B002FA5C6 /* Solar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Solar.swift; sourceTree = ""; }; - 35C36EFD225961D9002FA5C6 /* TimePeriod.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimePeriod.swift; sourceTree = ""; }; 35C36EFE225961D9002FA5C6 /* Date+Bundle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Date+Bundle.swift"; sourceTree = ""; }; - 35C36EFF225961D9002FA5C6 /* TimePeriodCollection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimePeriodCollection.swift; sourceTree = ""; }; 35C36F00225961D9002FA5C6 /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; - 35C36F01225961D9002FA5C6 /* TimePeriodGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimePeriodGroup.swift; sourceTree = ""; }; 35C36F02225961DA002FA5C6 /* Date+Components.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Date+Components.swift"; sourceTree = ""; }; 35C36F03225961DA002FA5C6 /* Date+TimeAgo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Date+TimeAgo.swift"; sourceTree = ""; }; 35C36F04225961DA002FA5C6 /* Integer+DateTools.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Integer+DateTools.swift"; sourceTree = ""; }; @@ -328,7 +321,6 @@ 35C36F09225961DA002FA5C6 /* Enums.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Enums.swift; sourceTree = ""; }; 35C36F0A225961DA002FA5C6 /* Date+Manipulations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Date+Manipulations.swift"; sourceTree = ""; }; 35C36F0B225961DA002FA5C6 /* Date+Format.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Date+Format.swift"; sourceTree = ""; }; - 35C36F0C225961DA002FA5C6 /* TimePeriodChain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimePeriodChain.swift; sourceTree = ""; }; 35C36F1E22596253002FA5C6 /* OneWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OneWindowController.swift; sourceTree = ""; }; 35C36F1F22596253002FA5C6 /* AppearanceViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppearanceViewController.swift; sourceTree = ""; }; 35C36F272259D6FA002FA5C6 /* ParentPanelController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParentPanelController.swift; sourceTree = ""; }; @@ -600,10 +592,6 @@ 35C36F09225961DA002FA5C6 /* Enums.swift */, 35C36F04225961DA002FA5C6 /* Integer+DateTools.swift */, 35C36F05225961DA002FA5C6 /* TimeChunk.swift */, - 35C36EFD225961D9002FA5C6 /* TimePeriod.swift */, - 35C36F0C225961DA002FA5C6 /* TimePeriodChain.swift */, - 35C36EFF225961D9002FA5C6 /* TimePeriodCollection.swift */, - 35C36F01225961D9002FA5C6 /* TimePeriodGroup.swift */, ); path = "Date Additions"; sourceTree = ""; @@ -1358,7 +1346,6 @@ 35C36F712259E185002FA5C6 /* NoTimezoneView.swift in Sources */, 35C36F2B2259D6FA002FA5C6 /* ParentPanelController.swift in Sources */, 35C36F582259DD8A002FA5C6 /* PanelTableView.swift in Sources */, - 35C36F0F225961DA002FA5C6 /* TimePeriodCollection.swift in Sources */, 35C36F18225961DA002FA5C6 /* Date+Comparators.swift in Sources */, 353B5BC52698B78A0023858D /* UpcomingEventStatusItemView.swift in Sources */, 35C36FA02259ED6D002FA5C6 /* CalendarHandler.swift in Sources */, @@ -1378,12 +1365,9 @@ 9AB6F1672259D23200A44663 /* PermissionsViewController.swift in Sources */, 3548C46126BEEFE400AFB533 /* UpcomingEventViewItem.swift in Sources */, 9AB6F1642259D1B900A44663 /* ParentViewController.swift in Sources */, - 35C36F1C225961DA002FA5C6 /* TimePeriodChain.swift in Sources */, 3508CCAA259A0027000E3530 /* StatusContainerView.swift in Sources */, - 35C36F11225961DA002FA5C6 /* TimePeriodGroup.swift in Sources */, 35C36EF922595F14002FA5C6 /* OnboardingParentViewController.swift in Sources */, 35C36F4E2259D981002FA5C6 /* DateFormatterManager.swift in Sources */, - 35C36F0D225961DA002FA5C6 /* TimePeriod.swift in Sources */, 35C36EFB2259616B002FA5C6 /* Solar.swift in Sources */, 35C36F662259DF4C002FA5C6 /* UpcomingEventView.swift in Sources */, 35C36EF522595F14002FA5C6 /* OnboardingSearchController.swift in Sources */, diff --git a/Clocker/Dependencies/Date Additions/TimePeriod.swift b/Clocker/Dependencies/Date Additions/TimePeriod.swift deleted file mode 100755 index 55f4c5c..0000000 --- a/Clocker/Dependencies/Date Additions/TimePeriod.swift +++ /dev/null @@ -1,667 +0,0 @@ -// -// TimePeriod.swift -// DateTools -// -// Created by Grayson Webster on 8/17/16. -// Copyright © 2016 Grayson Webster. All rights reserved. -// - -import Foundation - -/** - * In DateTools, time periods are represented by the TimePeriod protocol. - * Required variables and method impleementations are bound below. An inheritable - * implementation of the TimePeriodProtocol is available through the TimePeriodClass - * - * [Visit our github page](https://github.com/MatthewYork/DateTools#time-periods) for more information. - */ -public protocol TimePeriodProtocol { - // MARK: - Variables - - /** - * The start date for a TimePeriod representing the starting boundary of the time period - */ - var beginning: Date? { get set } - - /** - * The end date for a TimePeriod representing the ending boundary of the time period - */ - var end: Date? { get set } -} - -public extension TimePeriodProtocol { - // MARK: - Information - - /** - * True if the `TimePeriod`'s duration is zero - */ - var isMoment: Bool { - return beginning == end - } - - /** - * The duration of the `TimePeriod` in years. - * Returns the max int if beginning or end are nil. - */ - var years: Int { - if beginning != nil, end != nil { - return beginning!.yearsEarlier(than: end!) - } - return Int.max - } - - /** - * The duration of the `TimePeriod` in weeks. - * Returns the max int if beginning or end are nil. - */ - var weeks: Int { - if beginning != nil, end != nil { - return beginning!.weeksEarlier(than: end!) - } - return Int.max - } - - /** - * The duration of the `TimePeriod` in days. - * Returns the max int if beginning or end are nil. - */ - var days: Int { - if beginning != nil, end != nil { - return beginning!.daysEarlier(than: end!) - } - return Int.max - } - - /** - * The duration of the `TimePeriod` in hours. - * Returns the max int if beginning or end are nil. - */ - var hours: Int { - if beginning != nil, end != nil { - return beginning!.hoursEarlier(than: end!) - } - return Int.max - } - - /** - * The duration of the `TimePeriod` in minutes. - * Returns the max int if beginning or end are nil. - */ - var minutes: Int { - if beginning != nil, end != nil { - return beginning!.minutesEarlier(than: end!) - } - return Int.max - } - - /** - * The duration of the `TimePeriod` in seconds. - * Returns the max int if beginning or end are nil. - */ - var seconds: Int { - if beginning != nil, end != nil { - return beginning!.secondsEarlier(than: end!) - } - return Int.max - } - - /** - * The duration of the `TimePeriod` in a time chunk. - * Returns a time chunk with all zeroes if beginning or end are nil. - */ - var chunk: TimeChunk { - if beginning != nil, end != nil { - return beginning!.chunkBetween(date: end!) - } - return TimeChunk(seconds: 0, minutes: 0, hours: 0, days: 0, weeks: 0, months: 0, years: 0) - } - - /** - * The length of time between the beginning and end dates of the - * `TimePeriod` as a `TimeInterval`. - */ - var duration: TimeInterval { - if beginning != nil, end != nil { - return abs(beginning!.timeIntervalSince(end!)) - } - - return TimeInterval(Double.greatestFiniteMagnitude) - } - - // MARK: - Time Period Relationships - - /** - * The relationship of the self `TimePeriod` to the given `TimePeriod`. - * Relations are stored in Enums.swift. Formal defnitions available in the provided - * links: - * [GitHub](https://github.com/MatthewYork/DateTools#relationships), - * [CodeProject](http://www.codeproject.com/Articles/168662/Time-Period-Library-for-NET) - * - * - parameter period: The time period to compare to self - * - * - returns: The relationship between self and the given time period - */ - func relation(to period: TimePeriodProtocol) -> Relation { - // Make sure that all start and end points exist for comparison - if beginning != nil, end != nil, period.beginning != nil, period.end != nil { - // Make sure time periods are of positive durations - if beginning!.isEarlier(than: end!), period.beginning!.isEarlier(than: period.end!) { - // Make comparisons - if period.end!.isEarlier(than: beginning!) { - return .after - } else if period.end!.equals(beginning!) { - return .startTouching - } else if period.beginning!.isEarlier(than: beginning!), period.end!.isEarlier(than: end!) { - return .startInside - } else if period.beginning!.equals(beginning!), period.end!.isLater(than: end!) { - return .insideStartTouching - } else if period.beginning!.equals(beginning!), period.end!.isEarlier(than: end!) { - return .enclosingStartTouching - } else if period.beginning!.isLater(than: beginning!), period.end!.isEarlier(than: end!) { - return .enclosing - } else if period.beginning!.isLater(than: beginning!), period.end!.equals(end!) { - return .enclosingEndTouching - } else if period.beginning!.equals(beginning!), period.end!.equals(end!) { - return .exactMatch - } else if period.beginning!.isEarlier(than: beginning!), period.end!.isLater(than: end!) { - return .inside - } else if period.beginning!.isEarlier(than: beginning!), period.end!.equals(end!) { - return .insideEndTouching - } else if period.beginning!.isEarlier(than: end!), period.end!.isLater(than: end!) { - return .endInside - } else if period.beginning!.equals(end!), period.end!.isLater(than: end!) { - return .endTouching - } else if period.beginning!.isLater(than: end!) { - return .before - } - } - } - - return .none - } - - /** - * If `self.beginning` and `self.end` are equal to the beginning and end of the - * given `TimePeriod`. - * - * - parameter period: The time period to compare to self - * - * - returns: True if the periods are the same - */ - func equals(_ period: TimePeriodProtocol) -> Bool { - return beginning == period.beginning && end == period.end - } - - /** - * If the given `TimePeriod`'s beginning is before `self.beginning` and - * if the given 'TimePeriod`'s end is after `self.end`. - * - * - parameter period: The time period to compare to self - * - * - returns: True if self is inside of the given `TimePeriod` - */ - func isInside(of period: TimePeriodProtocol) -> Bool { - return period.beginning!.isEarlierThanOrEqual(to: beginning!) && period.end!.isLaterThanOrEqual(to: end!) - } - - /** - * If the given Date is after `self.beginning` and before `self.end`. - * - * - parameter period: The time period to compare to self - * - parameter interval: Whether the edge of the date is included in the calculation - * - * - returns: True if the given `TimePeriod` is inside of self - */ - func contains(_ date: Date, interval: Interval) -> Bool { - if interval == .open { - return beginning!.isEarlier(than: date) && end!.isLater(than: date) - } else if interval == .closed { - return (beginning!.isEarlierThanOrEqual(to: date) && end!.isLaterThanOrEqual(to: date)) - } - - return false - } - - /** - * If the given `TimePeriod`'s beginning is after `self.beginning` and - * if the given 'TimePeriod`'s after is after `self.end`. - * - * - parameter period: The time period to compare to self - * - * - returns: True if the given `TimePeriod` is inside of self - */ - func contains(_ period: TimePeriodProtocol) -> Bool { - return beginning!.isEarlierThanOrEqual(to: period.beginning!) && end!.isLaterThanOrEqual(to: period.end!) - } - - /** - * If self and the given `TimePeriod` share any sub-`TimePeriod`. - * - * - parameter period: The time period to compare to self - * - * - returns: True if there is a period of time that is shared by both `TimePeriod`s - */ - func overlaps(with period: TimePeriodProtocol) -> Bool { - // Outside -> Inside - if period.beginning!.isEarlier(than: beginning!), period.end!.isLater(than: beginning!) { - return true - } - // Enclosing - else if period.beginning!.isLaterThanOrEqual(to: beginning!), period.end!.isEarlierThanOrEqual(to: end!) { - return true - } - // Inside -> Out - else if period.beginning!.isEarlier(than: end!), period.end!.isLater(than: end!) { - return true - } - return false - } - - /** - * If self and the given `TimePeriod` overlap or the period's edges touch. - * - * - parameter period: The time period to compare to self - * - * - returns: True if there is a period of time or moment that is shared by both `TimePeriod`s - */ - func intersects(with period: TimePeriodProtocol) -> Bool { - return relation(to: period) != .after && relation(to: period) != .before - } - - /** - * If self and the given `TimePeriod` have no overlap or touching edges. - * - * - parameter period: The time period to compare to self - * - * - returns: True if there is a period of time between self and the given `TimePeriod` not contained by either period - */ - func hasGap(between period: TimePeriodProtocol) -> Bool { - return isBefore(period: period) || isAfter(period: period) - } - - /** - * The period of time between self and the given `TimePeriod` not contained by either. - * - * - parameter period: The time period to compare to self - * - * - returns: The gap between the periods. Zero if there is no gap. - */ - func gap(between period: TimePeriodProtocol) -> TimeInterval { - if end!.isEarlier(than: period.beginning!) { - return abs(end!.timeIntervalSince(period.beginning!)) - } else if period.end!.isEarlier(than: beginning!) { - return abs(period.end!.timeIntervalSince(beginning!)) - } - return 0 - } - - /** - * The period of time between self and the given `TimePeriod` not contained by either - * as a `TimeChunk`. - * - * - parameter period: The time period to compare to self - * - * - returns: The gap between the periods, zero if there is no gap - */ - func gap(between period: TimePeriodProtocol) -> TimeChunk? { - if end != nil, period.beginning != nil { - return (end?.chunkBetween(date: period.beginning!))! - } - return nil - } - - /** - * If self is after the given `TimePeriod` chronologically. (A gap must exist between the two). - * - * - parameter period: The time period to compare to self - * - * - returns: True if self is after the given `TimePeriod` - */ - func isAfter(period: TimePeriodProtocol) -> Bool { - return relation(to: period) == .after - } - - /** - * If self is before the given `TimePeriod` chronologically. (A gap must exist between the two). - * - * - parameter period: The time period to compare to self - * - * - returns: True if self is after the given `TimePeriod` - */ - func isBefore(period: TimePeriodProtocol) -> Bool { - return relation(to: period) == .before - } - - // MARK: - Shifts - - // MARK: In Place - - /** - * In place, shift the `TimePeriod` by a `TimeInterval` - * - * - parameter timeInterval: The time interval to shift the period by - */ - mutating func shift(by timeInterval: TimeInterval) { - beginning?.addTimeInterval(timeInterval) - end?.addTimeInterval(timeInterval) - } - - /** - * In place, shift the `TimePeriod` by a `TimeChunk` - * - * - parameter chunk: The time chunk to shift the period by - */ - mutating func shift(by chunk: TimeChunk) { - beginning = beginning?.add(chunk) - end = end?.add(chunk) - } - - // MARK: - Lengthen / Shorten - - // MARK: In Place - - /** - * In place, lengthen the `TimePeriod`, anchored at the beginning, end or center - * - * - parameter timeInterval: The time interval to lengthen the period by - * - parameter anchor: The anchor point from which to make the change - */ - mutating func lengthen(by timeInterval: TimeInterval, at anchor: Anchor) { - switch anchor { - case .beginning: - end = end?.addingTimeInterval(timeInterval) - case .center: - beginning = beginning?.addingTimeInterval(-timeInterval / 2.0) - end = end?.addingTimeInterval(timeInterval / 2.0) - case .end: - beginning = beginning?.addingTimeInterval(-timeInterval) - } - } - - /** - * In place, lengthen the `TimePeriod`, anchored at the beginning or end - * - * - parameter chunk: The time chunk to lengthen the period by - * - parameter anchor: The anchor point from which to make the change - */ - mutating func lengthen(by chunk: TimeChunk, at anchor: Anchor) { - switch anchor { - case .beginning: - end = end?.add(chunk) - case .center: - // Do not lengthen by TimeChunk at center - Swift.print("Mutation via chunk from center anchor is not supported.") - case .end: - beginning = beginning?.subtract(chunk) - } - } - - /** - * In place, shorten the `TimePeriod`, anchored at the beginning, end or center - * - * - parameter timeInterval: The time interval to shorten the period by - * - parameter anchor: The anchor point from which to make the change - */ - mutating func shorten(by timeInterval: TimeInterval, at anchor: Anchor) { - switch anchor { - case .beginning: - end = end?.addingTimeInterval(-timeInterval) - case .center: - beginning = beginning?.addingTimeInterval(timeInterval / 2.0) - end = end?.addingTimeInterval(-timeInterval / 2.0) - case .end: - beginning = beginning?.addingTimeInterval(timeInterval) - } - } - - /** - * In place, shorten the `TimePeriod`, anchored at the beginning or end - * - * - parameter chunk: The time chunk to shorten the period by - * - parameter anchor: The anchor point from which to make the change - */ - mutating func shorten(by chunk: TimeChunk, at anchor: Anchor) { - switch anchor { - case .beginning: - end = end?.subtract(chunk) - case .center: - // Do not shorten by TimeChunk at center - Swift.print("Mutation via chunk from center anchor is not supported.") - case .end: - beginning = beginning?.add(chunk) - } - } -} - -/** - * In DateTools, time periods are represented by the case TimePeriod class - * and come with a suite of initializaiton, manipulation, and comparison methods - * to make working with them a breeze. - * - * [Visit our github page](https://github.com/MatthewYork/DateTools#time-periods) for more information. - */ -open class TimePeriod: TimePeriodProtocol { - // MARK: - Variables - - /** - * The start date for a TimePeriod representing the starting boundary of the time period - */ - public var beginning: Date? - - /** - * The end date for a TimePeriod representing the ending boundary of the time period - */ - public var end: Date? - - // MARK: - Initializers - - init() {} - - init(beginning: Date?, end: Date?) { - self.beginning = beginning - self.end = end - } - - init(beginning: Date, duration: TimeInterval) { - self.beginning = beginning - end = beginning + duration - } - - init(end: Date, duration: TimeInterval) { - self.end = end - beginning = end.addingTimeInterval(-duration) - } - - init(beginning: Date, chunk: TimeChunk) { - self.beginning = beginning - end = beginning + chunk - } - - init(end: Date, chunk: TimeChunk) { - self.end = end - beginning = end - chunk - } - - init(chunk: TimeChunk) { - beginning = Date() - end = beginning?.add(chunk) - } - - // MARK: - Shifted - - /** - * Shift the `TimePeriod` by a `TimeInterval` - * - * - parameter timeInterval: The time interval to shift the period by - * - * - returns: The new, shifted `TimePeriod` - */ - func shifted(by timeInterval: TimeInterval) -> TimePeriod { - let timePeriod = TimePeriod() - timePeriod.beginning = beginning?.addingTimeInterval(timeInterval) - timePeriod.end = end?.addingTimeInterval(timeInterval) - return timePeriod - } - - /** - * Shift the `TimePeriod` by a `TimeChunk` - * - * - parameter chunk: The time chunk to shift the period by - * - * - returns: The new, shifted `TimePeriod` - */ - func shifted(by chunk: TimeChunk) -> TimePeriod { - let timePeriod = TimePeriod() - timePeriod.beginning = beginning?.add(chunk) - timePeriod.end = end?.add(chunk) - return timePeriod - } - - // MARK: - Lengthen / Shorten - - // MARK: New - - /** - * Lengthen the `TimePeriod` by a `TimeInterval` - * - * - parameter timeInterval: The time interval to lengthen the period by - * - parameter anchor: The anchor point from which to make the change - * - * - returns: The new, lengthened `TimePeriod` - */ - func lengthened(by timeInterval: TimeInterval, at anchor: Anchor) -> TimePeriod { - let timePeriod = TimePeriod() - switch anchor { - case .beginning: - timePeriod.beginning = beginning - timePeriod.end = end?.addingTimeInterval(timeInterval) - case .center: - timePeriod.beginning = beginning?.addingTimeInterval(-timeInterval) - timePeriod.end = end?.addingTimeInterval(timeInterval) - case .end: - timePeriod.beginning = beginning?.addingTimeInterval(-timeInterval) - timePeriod.end = end - } - - return timePeriod - } - - /** - * Lengthen the `TimePeriod` by a `TimeChunk` - * - * - parameter chunk: The time chunk to lengthen the period by - * - parameter anchor: The anchor point from which to make the change - * - * - returns: The new, lengthened `TimePeriod` - */ - func lengthened(by chunk: TimeChunk, at anchor: Anchor) -> TimePeriod { - let timePeriod = TimePeriod() - switch anchor { - case .beginning: - timePeriod.beginning = beginning - timePeriod.end = end?.add(chunk) - case .center: - Swift.print("Mutation via chunk from center anchor is not supported.") - case .end: - timePeriod.beginning = beginning?.add(-chunk) - timePeriod.end = end - } - - return timePeriod - } - - /** - * Shorten the `TimePeriod` by a `TimeInterval` - * - * - parameter timeInterval: The time interval to shorten the period by - * - parameter anchor: The anchor point from which to make the change - * - * - returns: The new, shortened `TimePeriod` - */ - func shortened(by timeInterval: TimeInterval, at anchor: Anchor) -> TimePeriod { - let timePeriod = TimePeriod() - switch anchor { - case .beginning: - timePeriod.beginning = beginning - timePeriod.end = end?.addingTimeInterval(-timeInterval) - case .center: - timePeriod.beginning = beginning?.addingTimeInterval(-timeInterval / 2) - timePeriod.end = end?.addingTimeInterval(timeInterval / 2) - case .end: - timePeriod.beginning = beginning?.addingTimeInterval(timeInterval) - timePeriod.end = end - } - - return timePeriod - } - - /** - * Shorten the `TimePeriod` by a `TimeChunk` - * - * - parameter chunk: The time chunk to shorten the period by - * - parameter anchor: The anchor point from which to make the change - * - * - returns: The new, shortened `TimePeriod` - */ - func shortened(by chunk: TimeChunk, at anchor: Anchor) -> TimePeriod { - let timePeriod = TimePeriod() - switch anchor { - case .beginning: - timePeriod.beginning = beginning - timePeriod.end = end?.subtract(chunk) - case .center: - Swift.print("Mutation via chunk from center anchor is not supported.") - case .end: - timePeriod.beginning = beginning?.add(-chunk) - timePeriod.end = end - } - - return timePeriod - } - - // MARK: - Operator Overloads - - /** - * Operator overload for checking if two `TimePeriod`s are equal - */ - static func == (leftAddend: TimePeriod, rightAddend: TimePeriod) -> Bool { - return leftAddend.equals(rightAddend) - } - - // Default anchor = beginning - /** - * Operator overload for lengthening a `TimePeriod` by a `TimeInterval` - */ - static func + (leftAddend: TimePeriod, rightAddend: TimeInterval) -> TimePeriod { - return leftAddend.lengthened(by: rightAddend, at: .beginning) - } - - /** - * Operator overload for lengthening a `TimePeriod` by a `TimeChunk` - */ - static func + (leftAddend: TimePeriod, rightAddend: TimeChunk) -> TimePeriod { - return leftAddend.lengthened(by: rightAddend, at: .beginning) - } - - // Default anchor = beginning - /** - * Operator overload for shortening a `TimePeriod` by a `TimeInterval` - */ - static func - (minuend: TimePeriod, subtrahend: TimeInterval) -> TimePeriod { - return minuend.shortened(by: subtrahend, at: .beginning) - } - - /** - * Operator overload for shortening a `TimePeriod` by a `TimeChunk` - */ - static func - (minuend: TimePeriod, subtrahend: TimeChunk) -> TimePeriod { - return minuend.shortened(by: subtrahend, at: .beginning) - } - - /** - * Operator overload for checking if a `TimePeriod` is equal to a `TimePeriodProtocol` - */ - static func == (left: TimePeriod, right: TimePeriodProtocol) -> Bool { - return left.equals(right) - } -} diff --git a/Clocker/Dependencies/Date Additions/TimePeriodChain.swift b/Clocker/Dependencies/Date Additions/TimePeriodChain.swift deleted file mode 100755 index 52a8be8..0000000 --- a/Clocker/Dependencies/Date Additions/TimePeriodChain.swift +++ /dev/null @@ -1,177 +0,0 @@ -// -// TimePeriodChain.swift -// DateTools -// -// Created by Grayson Webster on 8/17/16. -// Copyright © 2016 Grayson Webster. All rights reserved. -// - -import Foundation - -/** - * Time period chains serve as a tightly coupled set of time periods. They are - * always organized by start and end date, and have their own characteristics like - * a StartDate and EndDate that are extrapolated from the time periods within. Time - * period chains do not allow overlaps within their set of time periods. This type of - * group is ideal for modeling schedules like sequential meetings or appointments. - * - * [Visit our github page](https://github.com/MatthewYork/DateTools#time-period-chains) for more information. - */ -open class TimePeriodChain: TimePeriodGroup { - // MARK: - Chain Existence Manipulation - - /** - * Append a TimePeriodProtocol to the periods array and update the Chain's - * beginning and end. - * - * - parameter period: TimePeriodProtocol to add to the collection - */ - public func append(_ period: TimePeriodProtocol) { - let beginning = (periods.isEmpty == false) ? periods.last!.end! : period.beginning - - let newPeriod = TimePeriod(beginning: beginning!, duration: period.duration) - periods.append(newPeriod) - - // Update updateExtremes - if periods.count == 1 { - _beginning = period.beginning - _end = period.end - } else { - _end = _end?.addingTimeInterval(period.duration) - } - } - - /** - * Append a TimePeriodProtocol array to the periods array and update the Chain's - * beginning and end. - * - * - parameter periodArray: TimePeriodProtocol list to add to the collection - */ - public func append(contentsOf group: G) { - for period in group.periods { - let beginning = (periods.isEmpty == false) ? periods.last!.end! : period.beginning - - let newPeriod = TimePeriod(beginning: beginning!, duration: period.duration) - periods.append(newPeriod) - - // Update updateExtremes - if periods.count == 1 { - _beginning = period.beginning - _end = period.end - } else { - _end = _end?.addingTimeInterval(period.duration) - } - } - } - - /** - * Insert period into periods array at given index. - * - * - parameter newElement: The period to insert - * - parameter index: Index to insert period at - */ - public func insert(_ period: TimePeriodProtocol, at index: Int) { - // Check for special zero case which takes the beginning date - if index == 0, period.beginning != nil, period.end != nil { - // Insert new period - periods.insert(period, at: index) - } else if period.beginning != nil, period.end != nil { - // Insert new period - periods.insert(period, at: index) - } else { - Swift.print("All TimePeriods in a TimePeriodChain must contain a defined start and end date") - return - } - - // Shift all periods after inserted period - for i in 0 ..< periods.count { - if i > index, i > 0 { - let currentPeriod = TimePeriod(beginning: period.beginning, end: period.end) - periods[i].beginning = periods[i - 1].end - periods[i].end = periods[i].beginning!.addingTimeInterval(currentPeriod.duration) - } - } - - updateExtremes() - } - - /** - * Remove from period array at the given index. - * - * - parameter at: The index in the collection to remove - */ - public func remove(at index: Int) { - // Retrieve duration of period to be removed - let duration = periods[index].duration - - // Remove period - periods.remove(at: index) - - // Shift all periods after inserted period - for i in index ..< periods.count { - periods[i].shift(by: -duration) - } - updateExtremes() - } - - /** - * Remove all periods from period array. - */ - public func removeAll() { - periods.removeAll() - updateExtremes() - } - - // MARK: - Chain Content Manipulation - - /** - * In place, shifts all chain time periods by a given time interval - * - * - parameter duration: The time interval to shift the period by - */ - public func shift(by duration: TimeInterval) { - for var period in periods { - period.shift(by: duration) - } - - _beginning = _beginning?.addingTimeInterval(duration) - _end = _end?.addingTimeInterval(duration) - } - - override public func map(_ transform: (TimePeriodProtocol) throws -> T) rethrows -> [T] { - return try periods.map(transform) - } - - override public func filter(_ isIncluded: (TimePeriodProtocol) throws -> Bool) rethrows -> [TimePeriodProtocol] { - return try periods.filter(isIncluded) - } - - override internal func reduce(_ initialResult: Result, _ nextPartialResult: (Result, TimePeriodProtocol) throws -> Result) rethrows -> Result { - return try periods.reduce(initialResult, nextPartialResult) - } - - /** - * Removes the last object from the `TimePeriodChain` and returns it - * - */ - public func pop() -> TimePeriodProtocol? { - let period = periods.popLast() - updateExtremes() - - return period - } - - internal func updateExtremes() { - _beginning = periods.first?.beginning - _end = periods.last?.end - } - - // MARK: - Operator Overloads - - /** - * Operator overload for comparing `TimePeriodChain`s to each other - */ - public static func == (left: TimePeriodChain, right: TimePeriodChain) -> Bool { - return left.equals(right) - } -} diff --git a/Clocker/Dependencies/Date Additions/TimePeriodCollection.swift b/Clocker/Dependencies/Date Additions/TimePeriodCollection.swift deleted file mode 100755 index 349d1ce..0000000 --- a/Clocker/Dependencies/Date Additions/TimePeriodCollection.swift +++ /dev/null @@ -1,267 +0,0 @@ -// -// TimePeriodCollection.swift -// DateTools -// -// Created by Grayson Webster on 8/17/16. -// Copyright © 2016 Grayson Webster. All rights reserved. -// - -import Foundation - -/** - * Time period collections serve as loose sets of time periods. They are - * unorganized unless you decide to sort them, and have their own characteristics - * like a `beginning` and `end` that are extrapolated from the time periods within. Time - * period collections allow overlaps within their set of time periods. - * - * [Visit our github page](https://github.com/MatthewYork/DateTools#time-period-collections) for more information. - */ -open class TimePeriodCollection: TimePeriodGroup { - // MARK: - Collection Manipulation - - /** - * Append a TimePeriodProtocol to the periods array and check if the Collection's - * beginning and end should change. - * - * - parameter period: TimePeriodProtocol to add to the collection - */ - public func append(_ period: TimePeriodProtocol) { - periods.append(period) - updateExtremes(period: period) - } - - /** - * Append a TimePeriodProtocol array to the periods array and check if the Collection's - * beginning and end should change. - * - * - parameter periodArray: TimePeriodProtocol list to add to the collection - */ - public func append(_ periodArray: [TimePeriodProtocol]) { - for period in periodArray { - periods.append(period) - updateExtremes(period: period) - } - } - - /** - * Append a TimePeriodGroup's periods array to the periods array of self and check if the Collection's - * beginning and end should change. - * - * - parameter newPeriods: TimePeriodGroup to merge periods arrays with - */ - public func append(contentsOf newPeriods: C) { - for period in newPeriods as TimePeriodGroup { - periods.append(period) - updateExtremes(period: period) - } - } - - /** - * Insert period into periods array at given index. - * - * - parameter newElement: The period to insert - * - parameter index: Index to insert period at - */ - public func insert(_ newElement: TimePeriodProtocol, at index: Int) { - periods.insert(newElement, at: index) - updateExtremes(period: newElement) - } - - /** - * Remove from period array at the given index. - * - * - parameter at: The index in the collection to remove - */ - public func remove(at: Int) { - periods.remove(at: at) - updateExtremes() - } - - /** - * Remove all periods from period array. - */ - public func removeAll() { - periods.removeAll() - updateExtremes() - } - - // MARK: - Sorting - - // In place - /** - * Sort periods array in place by beginning - */ - public func sortByBeginning() { - sort { (period1: TimePeriodProtocol, period2: TimePeriodProtocol) -> Bool in - if period1.beginning == nil, period2.beginning == nil { - return false - } else if period1.beginning == nil { - return true - } else if period2.beginning == nil { - return false - } else { - return period2.beginning! < period1.beginning! - } - } - } - - /** - * Sort periods array in place - */ - public func sort(by areInIncreasingOrder: (TimePeriodProtocol, TimePeriodProtocol) -> Bool) { - periods.sort(by: areInIncreasingOrder) - } - - // New collection - /** - * Return collection with sorted periods array by beginning - * - * - returns: Collection with sorted periods - */ - public func sortedByBeginning() -> TimePeriodCollection { - let array = periods.sorted { (period1: TimePeriodProtocol, period2: TimePeriodProtocol) -> Bool in - if period1.beginning == nil, period2.beginning == nil { - return false - } else if period1.beginning == nil { - return true - } else if period2.beginning == nil { - return false - } else { - return period2.beginning! < period1.beginning! - } - } - let collection = TimePeriodCollection() - collection.append(array) - return collection - } - - /** - * Return collection with sorted periods array - * - * - returns: Collection with sorted periods - */ - public func sorted(by areInIncreasingOrder: (TimePeriodProtocol, TimePeriodProtocol) -> Bool) -> TimePeriodCollection { - let collection = TimePeriodCollection() - collection.append(periods.sorted(by: areInIncreasingOrder)) - return collection - } - - // MARK: - Collection Relationship - - // Potentially use .reduce() instead of these functions - /** - * Returns from the `TimePeriodCollection` a sub-collection of `TimePeriod`s - * whose start and end dates fall completely inside the interval of the given `TimePeriod`. - * - * - parameter period: The period to compare each other period against - * - * - returns: Collection of periods inside the given period - */ - public func allInside(in period: TimePeriodProtocol) -> TimePeriodCollection { - let collection = TimePeriodCollection() - // Filter by period - collection.periods = periods.filter { (timePeriod: TimePeriodProtocol) -> Bool in - timePeriod.isInside(of: period) - } - return collection - } - - /** - * Returns from the `TimePeriodCollection` a sub-collection of `TimePeriod`s containing - * the given date. - * - * - parameter date: The date to compare each period to - * - * - returns: Collection of periods intersected by the given date - */ - public func periodsIntersected(by date: Date) -> TimePeriodCollection { - let collection = TimePeriodCollection() - // Filter by period - collection.periods = periods.filter { (timePeriod: TimePeriodProtocol) -> Bool in - timePeriod.contains(date, interval: .closed) - } - return collection - } - - /** - * Returns from the `TimePeriodCollection` a sub-collection of `TimePeriod`s - * containing either the start date or the end date--or both--of the given `TimePeriod`. - * - * - parameter period: The period to compare each other period to - * - * - returns: Collection of periods intersected by the given period - */ - public func periodsIntersected(by period: TimePeriodProtocol) -> TimePeriodCollection { - let collection = TimePeriodCollection() - // Filter by periop - collection.periods = periods.filter { (timePeriod: TimePeriodProtocol) -> Bool in - timePeriod.intersects(with: period) - } - return collection - } - - // MARK: - Map - - public func map(_ transform: (TimePeriodProtocol) throws -> TimePeriodProtocol) rethrows -> TimePeriodCollection { - var mappedArray = [TimePeriodProtocol]() - mappedArray = try periods.map(transform) - let mappedCollection = TimePeriodCollection() - for period in mappedArray { - mappedCollection.periods.append(period) - mappedCollection.updateExtremes(period: period) - } - return mappedCollection - } - - // MARK: - Operator Overloads - - /** - * Operator overload for comparing `TimePeriodCollection`s to each other - */ - public static func == (left: TimePeriodCollection, right: TimePeriodCollection) -> Bool { - return left.equals(right) - } - - // MARK: - Helpers - - internal func updateExtremes(period: TimePeriodProtocol) { - // Check incoming period against previous beginning and end date - if count == 1 { - _beginning = period.beginning - _end = period.end - } else { - _beginning = nilOrEarlier(date1: _beginning, date2: period.beginning) - _end = nilOrLater(date1: _end, date2: period.end) - } - } - - internal func updateExtremes() { - if periods.isEmpty { - _beginning = nil - _end = nil - } else { - _beginning = periods[0].beginning - _end = periods[0].end - for i in 1 ..< periods.count { - _beginning = nilOrEarlier(date1: _beginning, date2: periods[i].beginning) - _end = nilOrEarlier(date1: _end, date2: periods[i].end) - } - } - } - - internal func nilOrEarlier(date1: Date?, date2: Date?) -> Date? { - if date1 == nil || date2 == nil { - return nil - } else { - return date1!.earlierDate(date2!) - } - } - - internal func nilOrLater(date1: Date?, date2: Date?) -> Date? { - if date1 == nil || date2 == nil { - return nil - } else { - return date1!.laterDate(date2!) - } - } -} diff --git a/Clocker/Dependencies/Date Additions/TimePeriodGroup.swift b/Clocker/Dependencies/Date Additions/TimePeriodGroup.swift deleted file mode 100755 index 27a40c1..0000000 --- a/Clocker/Dependencies/Date Additions/TimePeriodGroup.swift +++ /dev/null @@ -1,146 +0,0 @@ -// -// TimePeriodGroup.swift -// DateTools -// -// Created by Grayson Webster on 8/17/16. -// Copyright © 2016 Grayson Webster. All rights reserved. -// - -import Foundation - -/** - * Time period groups are the final abstraction of date and time in DateTools. Here, time - * periods are gathered and organized into something useful. There are two main types of time - * period groups, `TimePeriodCollection` and `TimePeriodChain`. - * - * [Visit our github page](https://github.com/MatthewYork/DateTools#time-period-groups) for more information. - */ -open class TimePeriodGroup: Sequence { - // MARK: - Variables - - /** - * The array of periods that define the group. - */ - internal var periods: [TimePeriodProtocol] = [] - - internal var _beginning: Date? - internal var _end: Date? - - /** - * The earliest beginning date of a `TimePeriod` in the group. - * Nil if any `TimePeriod` in group has a nil beginning date (indefinite). - * (Read Only) - */ - public var beginning: Date? { - return _beginning - } - - /** - * The latest end date of a `TimePeriod` in the group. - * Nil if any `TimePeriod` in group has a nil end date (indefinite). - * (Read Only) - */ - public var end: Date? { - return _end - } - - /** - * The number of periods in the periods array. - */ - public var count: Int { - return periods.count - } - - /** - * The total amount of time between the earliest and latest dates stored in the - * periods array. Nil if any beginning or end date in any contained period is nil. - */ - public var duration: TimeInterval? { - if beginning != nil, end != nil { - return end!.timeIntervalSince(beginning!) - } - return nil - } - - // MARK: - Initializers - - public init() {} - - // MARK: - Comparisons - - /** - * If `self.periods` contains the exact elements as the given group's periods array. - * - * - parameter group: The group to compare to self - * - * - returns: True if the periods arrays are the same - */ - public func equals(_ group: TimePeriodGroup) -> Bool { - return containSameElements(array1: periods, group.periods) - } - - // MARK: - Sequence Protocol - - public func makeIterator() -> IndexingIterator<[TimePeriodProtocol]> { - return periods.makeIterator() - } - - public func map(_ transform: (TimePeriodProtocol) throws -> T) rethrows -> [T] { - return try periods.map(transform) - } - - public func filter(_ isIncluded: (TimePeriodProtocol) throws -> Bool) rethrows -> [TimePeriodProtocol] { - return try periods.filter(isIncluded) - } - - public func forEach(_ body: (TimePeriodProtocol) throws -> Void) rethrows { - return try periods.forEach(body) - } - - public func split(maxSplits: Int, omittingEmptySubsequences: Bool, whereSeparator isSeparator: (TimePeriodProtocol) throws -> Bool) rethrows -> [AnySequence] { - return try periods.split(maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences, whereSeparator: isSeparator).map(AnySequence.init) - } - - subscript(index: Int) -> TimePeriodProtocol { - return periods[index] - } - - internal func reduce(_ initialResult: Result, _ nextPartialResult: (Result, TimePeriodProtocol) throws -> Result) rethrows -> Result { - return try periods.reduce(initialResult, nextPartialResult) - } - - internal func containSameElements(array1: [TimePeriodProtocol], _ array2: [TimePeriodProtocol]) -> Bool { - guard array1.count == array2.count else { - return false // No need to sorting if they already have different counts - } - - let compArray1: [TimePeriodProtocol] = array1.sorted { (period1: TimePeriodProtocol, period2: TimePeriodProtocol) -> Bool in - if period1.beginning == nil, period2.beginning == nil { - return false - } else if period1.beginning == nil { - return true - } else if period2.beginning == nil { - return false - } else { - return period2.beginning! < period1.beginning! - } - } - let compArray2: [TimePeriodProtocol] = array2.sorted { (period1: TimePeriodProtocol, period2: TimePeriodProtocol) -> Bool in - if period1.beginning == nil, period2.beginning == nil { - return false - } else if period1.beginning == nil { - return true - } else if period2.beginning == nil { - return false - } else { - return period2.beginning! < period1.beginning! - } - } - for x in 0 ..< compArray1.count { - if !compArray1[x].equals(compArray2[x]) { - return false - } - } - return true - } -}