You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
321 lines
9.2 KiB
321 lines
9.2 KiB
// |
|
// Date+Components.swift |
|
// DateToolsTests |
|
// |
|
// Created by Matthew York on 8/26/16. |
|
// Copyright © 2016 Matthew York. All rights reserved. |
|
// |
|
|
|
import Foundation |
|
|
|
/** |
|
* Extends the Date class by adding convenient accessors of calendar |
|
* components. Meta information about the date is also accessible via |
|
* several computed Bools. |
|
*/ |
|
public extension Date { |
|
/** |
|
* Convenient accessor of the date's `Calendar` components. |
|
* |
|
* - parameter component: The calendar component to access from the date |
|
* |
|
* - returns: The value of the component |
|
* |
|
*/ |
|
func component(_ component: Calendar.Component) -> Int { |
|
let calendar = Calendar.autoupdatingCurrent |
|
return calendar.component(component, from: self) |
|
} |
|
|
|
/** |
|
* Convenient accessor of the date's `Calendar` components ordinality. |
|
* |
|
* - parameter smaller: The smaller calendar component to access from the date |
|
* - parameter larger: The larger calendar component to access from the date |
|
* |
|
* - returns: The ordinal number of a smaller calendar component within a specified larger calendar component |
|
* |
|
*/ |
|
func ordinality(of smaller: Calendar.Component, in larger: Calendar.Component) -> Int? { |
|
let calendar = Calendar.autoupdatingCurrent |
|
return calendar.ordinality(of: smaller, in: larger, for: self) |
|
} |
|
|
|
/** |
|
* Use calendar components to determine how many units of a smaller component are inside 1 larger unit. |
|
* |
|
* Ex. If used on a date in the month of February in a leap year (regardless of the day), the method would |
|
* return 29 days. |
|
* |
|
* - parameter smaller: The smaller calendar component to access from the date |
|
* - parameter larger: The larger calendar component to access from the date |
|
* |
|
* - returns: The number of smaller units required to equal in 1 larger unit, given the date called on |
|
* |
|
*/ |
|
func unit(of smaller: Calendar.Component, in larger: Calendar.Component) -> Int? { |
|
let calendar = Calendar.autoupdatingCurrent |
|
var units = 1 |
|
var unitRange: Range<Int>? |
|
if larger.hashValue < smaller.hashValue { |
|
for x in larger.hashValue ..< smaller.hashValue { |
|
var stepLarger: Calendar.Component |
|
var stepSmaller: Calendar.Component |
|
|
|
switch x { |
|
case 0: |
|
stepLarger = Calendar.Component.era |
|
stepSmaller = Calendar.Component.year |
|
unitRange = calendar.range(of: stepSmaller, in: stepLarger, for: self) |
|
case 1: |
|
if smaller.hashValue > 2 { |
|
break |
|
} else { |
|
stepLarger = Calendar.Component.year |
|
stepSmaller = Calendar.Component.month |
|
unitRange = calendar.range(of: stepSmaller, in: stepLarger, for: self) |
|
} |
|
case 2: |
|
if larger.hashValue < 2 { |
|
if isInLeapYear { |
|
unitRange = Range(uncheckedBounds: (lower: 0, upper: 366)) |
|
} else { |
|
unitRange = Range(uncheckedBounds: (lower: 0, upper: 365)) |
|
} |
|
} else { |
|
stepLarger = Calendar.Component.month |
|
stepSmaller = Calendar.Component.day |
|
unitRange = calendar.range(of: stepSmaller, in: stepLarger, for: self) |
|
} |
|
case 3: |
|
stepLarger = Calendar.Component.day |
|
stepSmaller = Calendar.Component.hour |
|
unitRange = calendar.range(of: stepSmaller, in: stepLarger, for: self) |
|
case 4: |
|
stepLarger = Calendar.Component.hour |
|
stepSmaller = Calendar.Component.minute |
|
unitRange = calendar.range(of: stepSmaller, in: stepLarger, for: self) |
|
case 5: |
|
stepLarger = Calendar.Component.minute |
|
stepSmaller = Calendar.Component.second |
|
unitRange = calendar.range(of: stepSmaller, in: stepLarger, for: self) |
|
default: |
|
return nil |
|
} |
|
|
|
if unitRange?.count != nil { |
|
units *= (unitRange?.count)! |
|
} |
|
} |
|
return units |
|
} |
|
return nil |
|
} |
|
|
|
// MARK: - Components |
|
|
|
/** |
|
* Convenience getter for the date's `era` component |
|
*/ |
|
var era: Int { |
|
return component(.era) |
|
} |
|
|
|
/** |
|
* Convenience getter for the date's `year` component |
|
*/ |
|
var year: Int { |
|
return component(.year) |
|
} |
|
|
|
/** |
|
* Convenience getter for the date's `month` component |
|
*/ |
|
var month: Int { |
|
return component(.month) |
|
} |
|
|
|
/** |
|
* Convenience getter for the date's `week` component |
|
*/ |
|
var week: Int { |
|
return component(.weekday) |
|
} |
|
|
|
/** |
|
* Convenience getter for the date's `day` component |
|
*/ |
|
var day: Int { |
|
return component(.day) |
|
} |
|
|
|
/** |
|
* Convenience getter for the date's `hour` component |
|
*/ |
|
var hour: Int { |
|
return component(.hour) |
|
} |
|
|
|
/** |
|
* Convenience getter for the date's `minute` component |
|
*/ |
|
var minute: Int { |
|
return component(.minute) |
|
} |
|
|
|
/** |
|
* Convenience getter for the date's `second` component |
|
*/ |
|
var second: Int { |
|
return component(.second) |
|
} |
|
|
|
/** |
|
* Convenience getter for the date's `weekday` component |
|
*/ |
|
var weekday: Int { |
|
return component(.weekday) |
|
} |
|
|
|
/** |
|
* Convenience getter for the date's `weekdayOrdinal` component |
|
*/ |
|
var weekdayOrdinal: Int { |
|
return component(.weekdayOrdinal) |
|
} |
|
|
|
/** |
|
* Convenience getter for the date's `quarter` component |
|
*/ |
|
var quarter: Int { |
|
return component(.quarter) |
|
} |
|
|
|
/** |
|
* Convenience getter for the date's `weekOfYear` component |
|
*/ |
|
var weekOfMonth: Int { |
|
return component(.weekOfMonth) |
|
} |
|
|
|
/** |
|
* Convenience getter for the date's `weekOfYear` component |
|
*/ |
|
var weekOfYear: Int { |
|
return component(.weekOfYear) |
|
} |
|
|
|
/** |
|
* Convenience getter for the date's `yearForWeekOfYear` component |
|
*/ |
|
var yearForWeekOfYear: Int { |
|
return component(.yearForWeekOfYear) |
|
} |
|
|
|
/** |
|
* Convenience getter for the date's `daysInMonth` component |
|
*/ |
|
var daysInMonth: Int { |
|
let calendar = Calendar.autoupdatingCurrent |
|
let days = calendar.range(of: .day, in: .month, for: self) |
|
return days!.count |
|
} |
|
|
|
// MARK: - Set Components |
|
|
|
/** |
|
* Convenience setter for the date's `year` component |
|
*/ |
|
mutating func year(_ year: Int) { |
|
self = Date(year: year, month: month, day: day, hour: hour, minute: minute, second: second) |
|
} |
|
|
|
/** |
|
* Convenience setter for the date's `month` component |
|
*/ |
|
mutating func month(_ month: Int) { |
|
self = Date(year: year, month: month, day: day, hour: hour, minute: minute, second: second) |
|
} |
|
|
|
/** |
|
* Convenience setter for the date's `day` component |
|
*/ |
|
mutating func day(_ day: Int) { |
|
self = Date(year: year, month: month, day: day, hour: hour, minute: minute, second: second) |
|
} |
|
|
|
/** |
|
* Convenience setter for the date's `hour` component |
|
*/ |
|
mutating func hour(_ hour: Int) { |
|
self = Date(year: year, month: month, day: day, hour: hour, minute: minute, second: second) |
|
} |
|
|
|
/** |
|
* Convenience setter for the date's `minute` component |
|
*/ |
|
mutating func minute(_ minute: Int) { |
|
self = Date(year: year, month: month, day: day, hour: hour, minute: minute, second: second) |
|
} |
|
|
|
/** |
|
* Convenience setter for the date's `second` component |
|
*/ |
|
mutating func second(_ second: Int) { |
|
self = Date(year: year, month: month, day: day, hour: hour, minute: minute, second: second) |
|
} |
|
|
|
// MARK: - Bools |
|
|
|
/** |
|
* Determine if date is in a leap year |
|
*/ |
|
var isInLeapYear: Bool { |
|
let yearComponent = component(.year) |
|
|
|
if yearComponent % 400 == 0 { |
|
return true |
|
} |
|
if yearComponent % 100 == 0 { |
|
return false |
|
} |
|
if yearComponent % 4 == 0 { |
|
return true |
|
} |
|
return false |
|
} |
|
|
|
/** |
|
* Determine if date is within the current day |
|
*/ |
|
var isToday: Bool { |
|
let calendar = Calendar.autoupdatingCurrent |
|
return calendar.isDateInToday(self) |
|
} |
|
|
|
/** |
|
* Determine if date is within the day tomorrow |
|
*/ |
|
var isTomorrow: Bool { |
|
let calendar = Calendar.autoupdatingCurrent |
|
return calendar.isDateInTomorrow(self) |
|
} |
|
|
|
/** |
|
* Determine if date is within yesterday |
|
*/ |
|
var isYesterday: Bool { |
|
let calendar = Calendar.autoupdatingCurrent |
|
return calendar.isDateInYesterday(self) |
|
} |
|
|
|
/** |
|
* Determine if date is in a weekend |
|
*/ |
|
var isWeekend: Bool { |
|
if weekday == 7 || weekday == 1 { |
|
return true |
|
} |
|
return false |
|
} |
|
}
|
|
|