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.

331 lines
9.3 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)
break
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)
}
break
case 2:
if larger.hashValue < 2 {
if self.isInLeapYear {
unitRange = Range.init(uncheckedBounds: (lower: 0, upper: 366))
} else {
unitRange = Range.init(uncheckedBounds: (lower: 0, upper: 365))
}
} else {
stepLarger = Calendar.Component.month
stepSmaller = Calendar.Component.day
unitRange = calendar.range(of: stepSmaller, in: stepLarger, for: self)
}
break
case 3:
stepLarger = Calendar.Component.day
stepSmaller = Calendar.Component.hour
unitRange = calendar.range(of: stepSmaller, in: stepLarger, for: self)
break
case 4:
stepLarger = Calendar.Component.hour
stepSmaller = Calendar.Component.minute
unitRange = calendar.range(of: stepSmaller, in: stepLarger, for: self)
break
case 5:
stepLarger = Calendar.Component.minute
stepSmaller = Calendar.Component.second
unitRange = calendar.range(of: stepSmaller, in: stepLarger, for: self)
break
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.init(year: year, month: self.month, day: self.day, hour: self.hour, minute: self.minute, second: self.second)
}
/**
* Convenience setter for the date's `month` component
*/
mutating func month(_ month: Int) {
self = Date.init(year: self.year, month: month, day: self.day, hour: self.hour, minute: self.minute, second: self.second)
}
/**
* Convenience setter for the date's `day` component
*/
mutating func day(_ day: Int) {
self = Date.init(year: self.year, month: self.month, day: day, hour: self.hour, minute: self.minute, second: self.second)
}
/**
* Convenience setter for the date's `hour` component
*/
mutating func hour(_ hour: Int) {
self = Date.init(year: self.year, month: self.month, day: self.day, hour: hour, minute: self.minute, second: self.second)
}
/**
* Convenience setter for the date's `minute` component
*/
mutating func minute(_ minute: Int) {
self = Date.init(year: self.year, month: self.month, day: self.day, hour: self.hour, minute: minute, second: self.second)
}
/**
* Convenience setter for the date's `second` component
*/
mutating func second(_ second: Int) {
self = Date.init(year: self.year, month: self.month, day: self.day, hour: self.hour, minute: self.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
}
}