├── .gitignore ├── Assets └── CVCalendarKit.png ├── CVCalendarKit.podspec ├── CVCalendarKit ├── CVCalendarKitExtensions.swift └── CVCalendarKitOperators.swift ├── CVCalendarKitDemo └── Playground │ └── CVCalendarKitDemo.playground │ ├── Contents.swift │ ├── Sources │ ├── CVCalendarKitExtensions.swift │ └── CVCalendarKitOperators.swift │ ├── contents.xcplayground │ └── playground.xcworkspace │ └── contents.xcworkspacedata ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | 28 | # Carthage 29 | # 30 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 31 | # Carthage/Checkouts 32 | 33 | Carthage/Build 34 | -------------------------------------------------------------------------------- /Assets/CVCalendarKit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozharovsky/CVCalendarKit/686b3d52758a302e066ffc88647cb75aec0d142e/Assets/CVCalendarKit.png -------------------------------------------------------------------------------- /CVCalendarKit.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "CVCalendarKit" 3 | s.version = "0.1.5" 4 | s.summary = "A wrapper around NSDate which provides a convenience way for dealing with dates and NSCalendar." 5 | s.homepage = "https://github.com/Mozharovsky/CVCalendarKit" 6 | s.license = { :type => 'MIT' } 7 | s.author = { "Eugene Mozharovsky" => "mozharovsky@live.com" } 8 | s.platform = :ios, '7.0' 9 | s.source = { :git => "https://github.com/Mozharovsky/CVCalendarKit.git", :tag => s.version.to_s } 10 | s.source_files = 'CVCalendarKit/*' 11 | s.requires_arc = true 12 | end -------------------------------------------------------------------------------- /CVCalendarKit/CVCalendarKitExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CVCalendarKitExtensions.swift 3 | // CVCalendarKit 4 | // 5 | // Created by Eugene Mozharovsky on 05/05/15. 6 | // Copyright (c) 2015 Dwive. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | A wrapper around weekday raw value. The values match ones presented in NSCalendar. 13 | */ 14 | public enum Weekday: Int { 15 | case Sunday = 1 16 | case Monday 17 | case Tuesday 18 | case Wednesday 19 | case Thursday 20 | case Friday 21 | case Saturday 22 | 23 | func stringValue() -> String { 24 | switch self { 25 | case .Sunday: return "Sunday".localized 26 | case .Monday: return "Monday".localized 27 | case .Tuesday: return "Tuesday".localized 28 | case .Wednesday: return "Wednesday".localized 29 | case .Thursday: return "Thursday".localized 30 | case .Friday: return "Friday".localized 31 | case .Saturday: return "Saturday".localized 32 | } 33 | } 34 | } 35 | 36 | /** 37 | Date format for string description and date construction. 38 | */ 39 | public enum DateFormat: String { 40 | case YYMMDD = "yy-MM-dd" 41 | case YYYYMMDD = "yyyy-MM-dd" 42 | case YYMMMMDD = "yy-MMMM-dd" 43 | case YYMMMMDDDD = "yy-MMMM-dddd" 44 | case YYYYMMMMDD = "yyyy-MMMM-dddd" 45 | 46 | case DDMMYY = "dd-MM-yy" 47 | case DDMMYYYY = "dd-MM-yyyy" 48 | case DDMMMMYY = "dd-MMMM-yy" 49 | case DDDDMMMMYY = "dddd-MMMM-yy" 50 | case DDDDMMMMYYYY = "dddd-MMMM-yyyy" 51 | } 52 | 53 | private let YearUnit = NSCalendarUnit.Year 54 | private let MonthUnit = NSCalendarUnit.Month 55 | private let WeekUnit = NSCalendarUnit.WeekOfMonth 56 | private let WeekOfYearUnit = NSCalendarUnit.WeekOfYear 57 | private let WeekdayUnit = NSCalendarUnit.Weekday 58 | private let DayUnit = NSCalendarUnit.Day 59 | private let HourUnit = NSCalendarUnit.Hour 60 | private let MinuteUnit = NSCalendarUnit.Minute 61 | private let SecondUnit = NSCalendarUnit.Second 62 | private let AllUnits: NSCalendarUnit = [YearUnit , MonthUnit , WeekUnit , WeekOfYearUnit , WeekdayUnit , DayUnit, HourUnit, MinuteUnit, SecondUnit] 63 | 64 | public extension NSCalendar { 65 | /** 66 | Returns the NSDateComponents instance for all main units. 67 | 68 | :param: Date The date for components construction. 69 | :returns: The NSDateComponents instance for all main units. 70 | */ 71 | func allComponentsFromDate(date: NSDate) -> NSDateComponents { 72 | return components(AllUnits, fromDate: date) 73 | } 74 | } 75 | 76 | 77 | public extension NSDate { 78 | private typealias DateRange = (year: Int, month: Int, day: Int) 79 | 80 | /** 81 | Calculates the date values. 82 | 83 | :returns: A tuple with date year, month and day values. 84 | */ 85 | private func dateRange() -> DateRange { 86 | let calendar = NSCalendar.currentCalendar() 87 | let comps = calendar.allComponentsFromDate(self) 88 | 89 | return (comps.year, comps.month, comps.day) 90 | } 91 | 92 | /** 93 | Calculates the specific date values. 94 | 95 | :returns: A tuple with date hours and minutes. 96 | */ 97 | private typealias DateSpecificRange = (hours: Int, minutes: Int) 98 | private func dateSpecificRange() -> DateSpecificRange { 99 | let calendar = NSCalendar.currentCalendar() 100 | let comps = calendar.allComponentsFromDate(self) 101 | 102 | return (comps.hour, comps.minute) 103 | } 104 | 105 | var hour: DateUnit { 106 | get { 107 | return .Hour(self, dateSpecificRange().hours) 108 | } 109 | } 110 | 111 | var minute: DateUnit { 112 | get { 113 | return .Minute(self, dateSpecificRange().minutes) 114 | } 115 | } 116 | 117 | /** 118 | Current date weekday. 119 | */ 120 | var weekday: Weekday { 121 | get { 122 | return Weekday(rawValue: NSCalendar.currentCalendar().allComponentsFromDate(self).weekday)! 123 | } 124 | } 125 | 126 | /** 127 | Date year. 128 | */ 129 | var year: DateUnit { 130 | get { 131 | return .Year(self, dateRange().year) 132 | } 133 | } 134 | 135 | /** 136 | Date month. 137 | */ 138 | var month: DateUnit { 139 | get { 140 | return .Month(self, dateRange().month) 141 | } 142 | } 143 | 144 | /** 145 | Date day. 146 | */ 147 | var day: DateUnit { 148 | get { 149 | return .Day(self, dateRange().day) 150 | } 151 | } 152 | 153 | /** 154 | Returns the first date in the current date's month. 155 | 156 | :returns: The first date in the current date's month. 157 | */ 158 | func firstMonthDate() -> NSDate { 159 | return (self.day == 1) 160 | } 161 | 162 | /** 163 | Returns the last date in the current date's month. 164 | 165 | :returns: The las date in the current date's month. 166 | */ 167 | func lastMonthDate() -> NSDate { 168 | return ((firstMonthDate().month + 1).day - 1) 169 | } 170 | 171 | /** 172 | Returns the first date in the current date's year. 173 | 174 | :returns: The first date in the current date's year. 175 | */ 176 | func firstYearDate() -> NSDate { 177 | return ((NSDate().month == 1).day == 1) 178 | } 179 | 180 | /** 181 | Returns the last date in the current date's year. 182 | 183 | :returns: The last date in the current date's year. 184 | */ 185 | func lastYearDate() -> NSDate { 186 | return (((firstYearDate().month == 12).month + 1).day - 1) 187 | } 188 | 189 | convenience init?(date: NSDate, hour: Int, minute: Int) { 190 | let calendar = NSCalendar.currentCalendar() 191 | let comps = calendar.components([.Hour , .Minute], fromDate: date) 192 | comps.hour = 0 193 | comps.minute = 0 194 | 195 | let first = calendar.dateFromComponents(comps)! 196 | 197 | let compss = calendar.components([.Hour , .Minute], fromDate: first) 198 | compss.hour = hour 199 | compss.minute = minute 200 | 201 | if let result = calendar.dateFromComponents(compss) { 202 | self.init(timeIntervalSince1970: result.timeIntervalSince1970) 203 | } else { 204 | self.init() 205 | return nil 206 | } 207 | } 208 | 209 | /** 210 | Returns a date description string with the given locale and format. 211 | 212 | - parameter locale: The locale for converting the date. 213 | - parameter format: String format for the converted date. 214 | - parameter style: String style for the converted date. 215 | - returns: A date description string with the given locale and format. 216 | */ 217 | func descriptionWithLocale(locale: NSLocale? = nil, format: DateFormat = .YYMMDD, style: NSDateFormatterStyle?) -> String { 218 | let formatter = NSDateFormatter() 219 | formatter.dateFormat = format.rawValue 220 | 221 | if let formatterLocale = locale { 222 | formatter.locale = formatterLocale 223 | } 224 | 225 | if let formatterStyle = style { 226 | formatter.dateStyle = formatterStyle 227 | } 228 | 229 | return formatter.stringFromDate(self) 230 | } 231 | } 232 | 233 | public extension String { 234 | /** 235 | Returns an optional associated with date from the given string and format. 236 | 237 | - parameter format: Date format used for date conversion. 238 | - parameter style: Date style for date conversion. 239 | - returns: Either an NSDate instance or nil if a String can't be converted. 240 | */ 241 | func date(format: DateFormat, style: NSDateFormatterStyle? = .LongStyle) -> NSDate? { 242 | let formatter = NSDateFormatter() 243 | formatter.dateFormat = format.rawValue 244 | if let formatterStyle = style { 245 | formatter.dateStyle = formatterStyle 246 | } 247 | 248 | return formatter.dateFromString(self) 249 | } 250 | 251 | /** 252 | 253 | */ 254 | var localized: String { 255 | return NSLocalizedString(self, comment: self) 256 | } 257 | } -------------------------------------------------------------------------------- /CVCalendarKit/CVCalendarKitOperators.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CVCalendarKitOperators.swift 3 | // CVCalendarKit 4 | // 5 | // Created by Eugene Mozharovsky on 05/05/15. 6 | // Copyright (c) 2015 Dwive. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | An operating entity containing content information regarding its 13 | owner. It's used in the date management for date construction and 14 | comparison. 15 | 16 | Each enum case is associated with a date and a value. 17 | */ 18 | public enum DateUnit { 19 | case Year(NSDate, Int) 20 | case Month(NSDate, Int) 21 | case Day(NSDate, Int) 22 | case Hour(NSDate, Int) 23 | case Minute(NSDate, Int) 24 | 25 | /** 26 | :returns: An associated value with a particular case. 27 | */ 28 | public func value() -> Int { 29 | switch self { 30 | case .Year(_, let x): return x 31 | case .Month(_, let x): return x 32 | case .Day(_, let x): return x 33 | case .Hour(_, let x): return x 34 | case .Minute(_, let x): return x 35 | } 36 | } 37 | } 38 | 39 | /** 40 | A structure for marking an offset for a date. Used for date contruction. 41 | */ 42 | /** 43 | A structure for marking an offset for a date. Used for date contruction. 44 | */ 45 | public struct Offset { 46 | var year: Int 47 | var month: Int 48 | var day: Int 49 | var hour: Int 50 | var minute: Int 51 | } 52 | 53 | // MARK: - Helper functions 54 | 55 | private typealias DateOffset = (Offset, DateOperation) -> NSDate 56 | 57 | /** 58 | Constructs a date with the offset from the source date. 59 | 60 | :param: date The given date for applying the offset. 61 | 62 | :returns: A function for getting the date from the offset and the assignment operation. 63 | */ 64 | private func dateWithOffset(date: NSDate) -> DateOffset { 65 | let comps = NSCalendar.currentCalendar().allComponentsFromDate(date) 66 | return { offset, operation in 67 | comps.year = offset.year == 0 ? comps.year : operation(comps.year, offset.year) 68 | comps.month = offset.month == 0 ? comps.month : operation(comps.month, offset.month) 69 | comps.day = offset.day == 0 ? comps.day : operation(comps.day, offset.day) 70 | comps.hour = offset.hour == 0 ? comps.hour : operation(comps.hour, offset.hour) 71 | comps.minute = offset.minute == 0 ? comps.minute : operation(comps.minute, offset.minute) 72 | 73 | return NSCalendar.currentCalendar().dateFromComponents(comps)! 74 | } 75 | } 76 | private typealias DateOperation = (Int, Int) -> (Int) 77 | 78 | /** 79 | A bridge between construction function and the given options. 80 | 81 | :param: dateUnit A date unit providing the necessary data. 82 | :param: offset An offset for 83 | */ 84 | private func dateUnitOffset(dateUnit: DateUnit, offset: Int, operation: DateOperation) -> NSDate { 85 | let result: NSDate 86 | 87 | switch dateUnit { 88 | case .Year(let date, _): 89 | result = dateWithOffset(date)(Offset(year: offset, month: 0, day: 0, hour: 0, minute: 0), operation) 90 | case .Month(let date, _): 91 | result = dateWithOffset(date)(Offset(year: 0, month: offset, day: 0, hour: 0, minute: 0), operation) 92 | case .Day(let date, _): 93 | result = dateWithOffset(date)(Offset(year: 0, month: 0, day: offset, hour: 0, minute: 0), operation) 94 | case .Hour(let date, _): 95 | result = dateWithOffset(date)(Offset(year: 0, month: 0, day: 0, hour: offset, minute: 0), operation) 96 | case .Minute(let date, _): 97 | result = dateWithOffset(date)(Offset(year: 0, month: 0, day: 0, hour: 0, minute: offset), operation) 98 | } 99 | 100 | return result 101 | } 102 | 103 | private typealias ComparisonOperation = (Int, Int) -> Bool 104 | private typealias ResultMerge = (Bool, Bool, Bool) -> Bool 105 | private typealias ComparisonResult = (NSDate, NSDate) -> Bool 106 | 107 | /** 108 | Compares dates via return closure. 109 | 110 | :param: operation Comparison operation. 111 | :param: resultMerge The way of merging the results. 112 | :returns: A comparison function. 113 | */ 114 | private func compareWithOperation(operation: ComparisonOperation, resultMerge: ResultMerge) -> ComparisonResult { 115 | return { dateA, dateB in 116 | let resultA = operation(dateA.year.value(), dateB.year.value()) 117 | let resultB = operation(dateA.month.value(), dateB.month.value()) 118 | let resultC = operation(dateA.day.value(), dateB.day.value()) 119 | 120 | return resultMerge(resultA, resultB, resultC) 121 | } 122 | } 123 | 124 | // MARK: - DateUnit operators overload 125 | 126 | public func + (lhs: DateUnit, rhs: Int) -> NSDate { 127 | return dateUnitOffset(lhs, offset: rhs, operation: { x, y in x + y }) 128 | } 129 | 130 | public func - (lhs: DateUnit, rhs: Int) -> NSDate { 131 | return dateUnitOffset(lhs, offset: rhs, operation: { x, y in x - y }) 132 | } 133 | 134 | public func * (lhs: DateUnit, rhs: Int) -> NSDate { 135 | return dateUnitOffset(lhs, offset: rhs, operation: { x, y in x * y }) 136 | } 137 | 138 | public func / (lhs: DateUnit, rhs: Int) -> NSDate { 139 | return dateUnitOffset(lhs, offset: rhs, operation: { x, y in x / y }) 140 | } 141 | 142 | public func == (lhs: DateUnit, rhs: Int) -> NSDate { 143 | return dateUnitOffset(lhs, offset: rhs, operation: { _, y in y }) 144 | } 145 | 146 | // MARK: - NSDate operators overload 147 | 148 | public func == (lhs: NSDate, rhs: NSDate) -> Bool { 149 | return compareWithOperation({ $0 == $1 }, resultMerge: { $0 && $1 && $2 })(lhs, rhs) 150 | } 151 | 152 | public func > (lhs: NSDate, rhs: NSDate) -> Bool { 153 | return compareWithOperation({ $0 > $1 }, resultMerge: { $0 || $1 || $2 })(lhs, rhs) 154 | } 155 | 156 | public func >= (lhs: NSDate, rhs: NSDate) -> Bool { 157 | return compareWithOperation({ $0 > $1 || lhs == rhs }, resultMerge: { $0 || $1 || $2 })(lhs, rhs) 158 | } 159 | 160 | public func < (lhs: NSDate, rhs: NSDate) -> Bool { 161 | return compareWithOperation({ $0 < $1 }, resultMerge: { $0 || $1 || $2 })(lhs, rhs) 162 | } 163 | 164 | public func <= (lhs: NSDate, rhs: NSDate) -> Bool { 165 | return compareWithOperation({ $0 < $1 || lhs == rhs }, resultMerge: { $0 || $1 || $2 })(lhs, rhs) 166 | } 167 | 168 | public func != (lhs: NSDate, rhs: NSDate) -> Bool { 169 | return !(lhs == rhs) 170 | } -------------------------------------------------------------------------------- /CVCalendarKitDemo/Playground/CVCalendarKitDemo.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //: Playground - noun: a place where people can play 2 | 3 | import UIKit 4 | 5 | /// Current date. 6 | let today = NSDate() 7 | 8 | /// Day operations. 9 | let tomorrow = today.day + 1 10 | let yesterday = today.day - 1 11 | 12 | /// Month operations. 13 | let monthAhead = today.month + 1 14 | let monthAgo = today.month - 1 15 | 16 | /// Year operations. 17 | let yearAhead = today.year + 1 18 | let yearAgo = today.year - 1 19 | 20 | /// Multiplication and Division. 21 | let multipliedDate = today.day * 5 22 | let dividedDate = today.month / 5 23 | 24 | /// Trailing operations. 25 | let dayAheadMonthAgo = (today.day + 1).month - 1 26 | let yearAheadTwoMonthsAgoFiveDaysAhead = ((today.year + 1).month - 2).day + 5 27 | 28 | /// NSDate comparison. 29 | today == yesterday 30 | today > yesterday 31 | yesterday <= tomorrow 32 | tomorrow != today 33 | 34 | /// Convenience stuff. 35 | let firstDateInCurrentMonth = today.firstMonthDate() 36 | let lastDateInCurrentMonth = today.lastMonthDate() 37 | let firstDateInCurrentYear = today.firstYearDate() 38 | let lastDateInCurrentYear = today.lastYearDate() 39 | 40 | /// Date construction by assigning values. 41 | let customDate = ((today.day == 21).month == 5).year == 1997 42 | 43 | /// Date unit values (year, month, day). 44 | let todaysYear = today.year.value() 45 | let todaysMonth = today.month.value() 46 | let todaysDay = today.day.value() 47 | 48 | /// NSDate+Weekday. 49 | let todaysWeekday = today.weekday // Enum value. 50 | let todaysWeekdayRaw = today.weekday.rawValue // Raw value. 51 | 52 | /// Date description. 53 | let date = (NSDate().month == 5).descriptionWithLocale(nil, format: .DDMMYY, style: nil) 54 | 55 | /// Date from String (its description). 56 | if let myDate = "May 21, 1997".date(.DDMMYY, style: .MediumStyle) { 57 | myDate 58 | } -------------------------------------------------------------------------------- /CVCalendarKitDemo/Playground/CVCalendarKitDemo.playground/Sources/CVCalendarKitExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CVCalendarKitExtensions.swift 3 | // CVCalendarKit 4 | // 5 | // Created by Eugene Mozharovsky on 05/05/15. 6 | // Copyright (c) 2015 Dwive. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | A wrapper around weekday raw value. The values match ones presented in NSCalendar. 13 | */ 14 | public enum Weekday: Int { 15 | case Sunday = 1 16 | case Monday 17 | case Tuesday 18 | case Wednesday 19 | case Thursday 20 | case Friday 21 | case Saturday 22 | } 23 | 24 | /** 25 | Date format for string description and date construction. 26 | */ 27 | public enum DateFormat: String { 28 | case YYMMDD = "yy-MM-dd" 29 | case YYYYMMDD = "yyyy-MM-dd" 30 | case YYMMMMDD = "yy-MMMM-dd" 31 | case YYMMMMDDDD = "yy-MMMM-dddd" 32 | case YYYYMMMMDD = "yyyy-MMMM-dddd" 33 | 34 | case DDMMYY = "dd-MM-yy" 35 | case DDMMYYYY = "dd-MM-yyyy" 36 | case DDMMMMYY = "dd-MMMM-yy" 37 | case DDDDMMMMYY = "dddd-MMMM-yy" 38 | case DDDDMMMMYYYY = "dddd-MMMM-yyyy" 39 | } 40 | 41 | private let YearUnit = NSCalendarUnit.CalendarUnitYear 42 | private let MonthUnit = NSCalendarUnit.CalendarUnitMonth 43 | private let WeekUnit = NSCalendarUnit.CalendarUnitWeekOfMonth 44 | private let WeekOfYearUnit = NSCalendarUnit.CalendarUnitWeekOfYear 45 | private let WeekdayUnit = NSCalendarUnit.CalendarUnitWeekday 46 | private let DayUnit = NSCalendarUnit.CalendarUnitDay 47 | private let HourUnit = NSCalendarUnit.CalendarUnitHour 48 | private let MinuteUnit = NSCalendarUnit.CalendarUnitMinute 49 | private let SecondUnit = NSCalendarUnit.CalendarUnitSecond 50 | private let AllUnits = YearUnit | MonthUnit | WeekUnit | WeekOfYearUnit | WeekdayUnit | DayUnit | HourUnit | MinuteUnit | DayUnit 51 | 52 | public extension NSCalendar { 53 | /** 54 | Returns the NSDateComponents instance for all main units. 55 | 56 | :param: Date The date for components construction. 57 | :returns: The NSDateComponents instance for all main units. 58 | */ 59 | func allComponentsFromDate(date: NSDate) -> NSDateComponents { 60 | return components(AllUnits, fromDate: date) 61 | } 62 | } 63 | 64 | 65 | public extension NSDate { 66 | private typealias DateRange = (year: Int, month: Int, day: Int) 67 | 68 | /** 69 | Calculates the date values. 70 | 71 | :returns: A tuple with date year, month and day values. 72 | */ 73 | private func dateRange() -> DateRange { 74 | let calendar = NSCalendar.currentCalendar() 75 | let comps = calendar.allComponentsFromDate(self) 76 | 77 | return (comps.year, comps.month, comps.day) 78 | } 79 | 80 | /** 81 | Current date weekday. 82 | */ 83 | var weekday: Weekday { 84 | get { 85 | return Weekday(rawValue: NSCalendar.currentCalendar().allComponentsFromDate(self).weekday)! 86 | } 87 | } 88 | 89 | /** 90 | Date year. 91 | */ 92 | var year: DateUnit { 93 | get { 94 | return .Year(self, dateRange().year) 95 | } 96 | } 97 | 98 | /** 99 | Date month. 100 | */ 101 | var month: DateUnit { 102 | get { 103 | return .Month(self, dateRange().month) 104 | } 105 | } 106 | 107 | /** 108 | Date day. 109 | */ 110 | var day: DateUnit { 111 | get { 112 | return .Day(self, dateRange().day) 113 | } 114 | } 115 | 116 | /** 117 | Returns the first date in the current date's month. 118 | 119 | :returns: The first date in the current date's month. 120 | */ 121 | func firstMonthDate() -> NSDate { 122 | return (self.day == 1) 123 | } 124 | 125 | /** 126 | Returns the last date in the current date's month. 127 | 128 | :returns: The las date in the current date's month. 129 | */ 130 | func lastMonthDate() -> NSDate { 131 | return ((firstMonthDate().month + 1).day - 1) 132 | } 133 | 134 | /** 135 | Returns the first date in the current date's year. 136 | 137 | :returns: The first date in the current date's year. 138 | */ 139 | func firstYearDate() -> NSDate { 140 | return ((NSDate().month == 1).day == 1) 141 | } 142 | 143 | /** 144 | Returns the last date in the current date's year. 145 | 146 | :returns: The last date in the current date's year. 147 | */ 148 | func lastYearDate() -> NSDate { 149 | return (((firstYearDate().month == 12).month + 1).day - 1) 150 | } 151 | 152 | /** 153 | Returns a date description string with the given locale and format. 154 | 155 | :param: locale The locale for converting the date. 156 | :param: format String format for the converted date. 157 | :param: style String style for the converted date. 158 | :returns: A date description string with the given locale and format. 159 | */ 160 | func descriptionWithLocale(_ locale: NSLocale? = nil, format: DateFormat = .YYMMDD, style: NSDateFormatterStyle?) -> String { 161 | let formatter = NSDateFormatter() 162 | formatter.dateFormat = format.rawValue 163 | 164 | if let formatterLocale = locale { 165 | formatter.locale = formatterLocale 166 | } 167 | 168 | if let formatterStyle = style { 169 | formatter.dateStyle = formatterStyle 170 | } 171 | 172 | return formatter.stringFromDate(self) 173 | } 174 | } 175 | 176 | public extension String { 177 | /** 178 | Returns an optional associated with date from the given string and format. 179 | 180 | :param: format Date format used for date conversion. 181 | :param: style Date style for date conversion. 182 | :returns: Either an NSDate instance or nil if a String can't be converted. 183 | */ 184 | func date(format: DateFormat, style: NSDateFormatterStyle? = .LongStyle) -> NSDate? { 185 | let formatter = NSDateFormatter() 186 | formatter.dateFormat = format.rawValue 187 | if let formatterStyle = style { 188 | formatter.dateStyle = formatterStyle 189 | } 190 | 191 | return formatter.dateFromString(self) 192 | } 193 | } -------------------------------------------------------------------------------- /CVCalendarKitDemo/Playground/CVCalendarKitDemo.playground/Sources/CVCalendarKitOperators.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CVCalendarKitOperators.swift 3 | // CVCalendarKit 4 | // 5 | // Created by Eugene Mozharovsky on 05/05/15. 6 | // Copyright (c) 2015 Dwive. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | An operating entity containing content information regarding its 13 | owner. It's used in the date management for date construction and 14 | comparison. 15 | 16 | Each enum case is associated with a date and a value. 17 | */ 18 | public enum DateUnit { 19 | case Year(NSDate, Int) 20 | case Month(NSDate, Int) 21 | case Day(NSDate, Int) 22 | 23 | /** 24 | :returns: An associated value with a particular case. 25 | */ 26 | public func value() -> Int { 27 | switch self { 28 | case .Year(_, let x): return x 29 | case .Month(_, let x): return x 30 | case .Day(_, let x): return x 31 | } 32 | } 33 | } 34 | 35 | /** 36 | A structure for marking an offset for a date. Used for date contruction. 37 | */ 38 | public struct Offset { 39 | var year: Int 40 | var month: Int 41 | var day: Int 42 | } 43 | 44 | // MARK: - Helper functions 45 | 46 | private typealias DateOffset = (Offset, DateOperation) -> NSDate 47 | 48 | /** 49 | Constructs a date with the offset from the source date. 50 | 51 | :param: date The given date for applying the offset. 52 | 53 | :returns: A function for getting the date from the offset and the assignment operation. 54 | */ 55 | private func dateWithOffset(date: NSDate) -> DateOffset { 56 | let comps = NSCalendar.currentCalendar().allComponentsFromDate(date) 57 | return { offset, operation in 58 | comps.year = offset.year == 0 ? comps.year : operation(comps.year, offset.year) 59 | comps.month = offset.month == 0 ? comps.month : operation(comps.month, offset.month) 60 | comps.day = offset.day == 0 ? comps.day : operation(comps.day, offset.day) 61 | 62 | return NSCalendar.currentCalendar().dateFromComponents(comps)! 63 | } 64 | } 65 | 66 | private typealias DateOperation = (Int, Int) -> (Int) 67 | 68 | /** 69 | A bridge between construction function and the given options. 70 | 71 | :param: dateUnit A date unit providing the necessary data. 72 | :param: offset An offset for 73 | */ 74 | private func dateUnitOffset(dateUnit: DateUnit, offset: Int, operation: DateOperation) -> NSDate { 75 | let result: NSDate 76 | 77 | switch dateUnit { 78 | case .Year(let date, let value): 79 | result = dateWithOffset(date)(Offset(year: offset, month: 0, day: 0), operation) 80 | case .Month(let date, let value): 81 | result = dateWithOffset(date)(Offset(year: 0, month: offset, day: 0), operation) 82 | case .Day(let date, let value): 83 | result = dateWithOffset(date)(Offset(year: 0, month: 0, day: offset), operation) 84 | } 85 | 86 | return result 87 | } 88 | 89 | private typealias ComparisonOperation = (Int, Int) -> Bool 90 | private typealias ResultMerge = (Bool, Bool, Bool) -> Bool 91 | private typealias ComparisonResult = (NSDate, NSDate) -> Bool 92 | 93 | /** 94 | Compares dates via return closure. 95 | 96 | :param: operation Comparison operation. 97 | :param: resultMerge The way of merging the results. 98 | :returns: A comparison function. 99 | */ 100 | private func compareWithOperation(operation: ComparisonOperation, resultMerge: ResultMerge) -> ComparisonResult { 101 | return { dateA, dateB in 102 | let resultA = operation(dateA.year.value(), dateB.year.value()) 103 | let resultB = operation(dateA.month.value(), dateB.month.value()) 104 | let resultC = operation(dateA.day.value(), dateB.day.value()) 105 | 106 | return resultMerge(resultA, resultB, resultC) 107 | } 108 | } 109 | 110 | // MARK: - DateUnit operators overload 111 | 112 | public func + (lhs: DateUnit, rhs: Int) -> NSDate { 113 | return dateUnitOffset(lhs, rhs, { x, y in x + y }) 114 | } 115 | 116 | public func - (lhs: DateUnit, rhs: Int) -> NSDate { 117 | return dateUnitOffset(lhs, rhs, { x, y in x - y }) 118 | } 119 | 120 | public func * (lhs: DateUnit, rhs: Int) -> NSDate { 121 | return dateUnitOffset(lhs, rhs, { x, y in x * y }) 122 | } 123 | 124 | public func / (lhs: DateUnit, rhs: Int) -> NSDate { 125 | return dateUnitOffset(lhs, rhs, { x, y in x / y }) 126 | } 127 | 128 | public func == (lhs: DateUnit, rhs: Int) -> NSDate { 129 | return dateUnitOffset(lhs, rhs, { _, y in y }) 130 | } 131 | 132 | // MARK: - NSDate operators overload 133 | 134 | public func == (lhs: NSDate, rhs: NSDate) -> Bool { 135 | return compareWithOperation({ $0 == $1 }, { $0 && $1 && $2 })(lhs, rhs) 136 | } 137 | 138 | public func > (lhs: NSDate, rhs: NSDate) -> Bool { 139 | return compareWithOperation({ $0 > $1 }, { $0 || $1 || $2 })(lhs, rhs) 140 | } 141 | 142 | public func >= (lhs: NSDate, rhs: NSDate) -> Bool { 143 | return compareWithOperation({ $0 > $1 || lhs == rhs }, { $0 || $1 || $2 })(lhs, rhs) 144 | } 145 | 146 | public func < (lhs: NSDate, rhs: NSDate) -> Bool { 147 | return compareWithOperation({ $0 < $1 }, { $0 || $1 || $2 })(lhs, rhs) 148 | } 149 | 150 | public func <= (lhs: NSDate, rhs: NSDate) -> Bool { 151 | return compareWithOperation({ $0 < $1 || lhs == rhs }, { $0 || $1 || $2 })(lhs, rhs) 152 | } 153 | 154 | public func != (lhs: NSDate, rhs: NSDate) -> Bool { 155 | return !(lhs == rhs) 156 | } -------------------------------------------------------------------------------- /CVCalendarKitDemo/Playground/CVCalendarKitDemo.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CVCalendarKitDemo/Playground/CVCalendarKitDemo.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Eugene Mozharovsky 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ![](https://raw.githubusercontent.com/Mozharovsky/CVCalendarKit/9364bf1f7b7f70a632f5b57e2bbb7b9f85500109/Assets/CVCalendarKit.png) 3 | 4 | CVCalendarKit is a wrapper around NSDate which provides a convenience way for dealing with dates through overloaded operators and extensions. 5 | 6 | ## Features 7 | 8 | Currently available features. 9 | 10 | * DateUnit operations (year, month, day) – multiplication, division, addition, subtraction 11 | * Trailing operations 12 | * NSDate comparison 13 | * NSDate convenience stuff 14 | * Date construction with custom values 15 | * Date construction with String 16 | * Date unit values 17 | * Weekdays 18 | 19 | Further changes. 20 | 21 | - [ ] NSCalendar wrapper 22 | - [ ] Simplifyig the process of working with events 23 | - [ ] Reading/Writing calendar data 24 | 25 | ## Setup 26 | 27 |

Requirements.

28 | * Swift 1.2 29 | * iOS 7 or higher 30 | 31 |

CocoaPods.

32 | 33 | ```ruby 34 | pod 'CVCalendarKit', '~> 0.1.5' 35 | ``` 36 | 37 |

Manual setup.

38 | 39 | Download CVCalendarKit project source code and add CVCalendarKit folder into your target (copy if needed). 40 | ## Usage 41 | 42 | Using CVCalendarKit is extremely easy and intuitive. All you need is an instance of a NSDate. 43 | 44 | ```swift 45 | /// Current date. 46 | let today = NSDate() 47 | ``` 48 | 49 | Now you can use addition and substraction on a DateUnit. 50 | ```swift 51 | /// Day operations. 52 | let tomorrow = today.day + 1 53 | let yesterday = today.day - 1 54 | 55 | /// Month operations. 56 | let monthAhead = today.month + 1 57 | let monthAgo = today.month - 1 58 | 59 | /// Year operations. 60 | let yearAhead = today.year + 1 61 | let yearAgo = today.year - 1 62 | ``` 63 | 64 | Or even crazier operations! 65 | ```swift 66 | /// Multiplication and Division. 67 | let multipliedDate = today.day * 5 68 | let dividedDate = today.month / 5 69 | ``` 70 | 71 | You can get really difficult calculations with trailing. 72 | ```swift 73 | /// Trailing operations. 74 | let dayAheadMonthAgo = (today.day + 1).month - 1 75 | let yearAheadTwoMonthsAgoFiveDaysAhead = ((today.year + 1).month - 2).day + 5 76 | ``` 77 | 78 | NSDate `String` description. 79 | ```swift 80 | /// Date description. 81 | let date = (NSDate().month == 5).descriptionWithLocale(nil, format: .DDMMYY, style: nil) 82 | ``` 83 | 84 | Constructing a date from its description `String`. 85 | ```swift 86 | /// Date from String (its description). 87 | if let myDate = "May 21, 1997".date(.DDMMYY, style: .MediumStyle) { 88 | // Further stuff... 89 | } 90 | ``` 91 | 92 | Do you need to compare NSDate instances? Here you go! 93 | ```swift 94 | /// NSDate comparison. 95 | today == yesterday 96 | today > yesterday 97 | yesterday <= tomorrow 98 | tomorrow != today 99 | ``` 100 | 101 | You can also get the first/last date in your date's month/year. 102 | ```swift 103 | /// Convenience stuff. 104 | let firstDateInCurrentMonth = today.firstMonthDate() 105 | let lastDateInCurrentMonth = today.lastMonthDate() 106 | let firstDateInCurrentYear = today.firstYearDate() 107 | let lastDateInCurrentYear = today.lastYearDate() 108 | ``` 109 | 110 | Custom date can be constructed using `==` overloaded operator on NSDate objects. 111 | ```swift 112 | /// Date construction by assigning values. 113 | let customDate = ((today.day == 21).month == 5).year == 1997 114 | ``` 115 | 116 | Accessing date units' values. 117 | ```swift 118 | /// Date unit values (year, month, day). 119 | let todaysYear = today.year.value() 120 | let todaysMonth = today.month.value() 121 | let todaysDay = today.day.value() 122 | ``` 123 | 124 | And getting weekday enum/raw value. 125 | ```swift 126 | /// NSDate+Weekday. 127 | let todaysWeekday = today.weekday // Enum value. 128 | let todaysWeekdayRaw = today.weekday.rawValue // Raw value. 129 | ``` 130 | 131 | ## Acknowledgments 132 | 133 | * Author [Eugene Mozharovsky](https://github.com/Mozharovsky) 134 | * Inspired by [Timepiece](https://github.com/naoty/Timepiece) and [SwiftMoment](https://github.com/akosma/SwiftMoment) 135 | 136 | ## License 137 | 138 | CVCalendarKit is released under the MIT license. For more information see the [LICENSE](https://github.com/Mozharovsky/CVCalendarKit/blob/master/LICENSE) file. 139 | --------------------------------------------------------------------------------