From 53a09221dcc066d6f161412a5a6df707d745398d Mon Sep 17 00:00:00 2001 From: Xin Hong Date: Thu, 14 Apr 2016 15:20:47 +0800 Subject: [PATCH] support rdate --- README.md | 22 ++++++-- RRuleSwift.xcodeproj/project.pbxproj | 4 ++ RRuleSwift/Generators.swift | 12 ++++- RRuleSwift/InclusionDate.swift | 53 +++++++++++++++++++ RRuleSwift/RecurrenceRule.swift | 5 +- RRuleSwift/Supporting Files/Info.plist | 2 +- RRuleSwiftExample/Info.plist | 4 +- .../RRuleExample.playground/Contents.swift | 13 ++++- .../timeline.xctimeline | 26 ++++++--- 9 files changed, 124 insertions(+), 17 deletions(-) create mode 100644 RRuleSwift/InclusionDate.swift diff --git a/README.md b/README.md index 1931869..00bdb51 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ recurrenceRule.byweekday = ... recurrenceRule.byhour = ... recurrenceRule.byminute = ... recurrenceRule.bysecond = ... +recurrenceRule.rdate = ... recurrenceRule.exdate = ... ``` @@ -47,8 +48,20 @@ print(ruleString) // RRULE:FREQ=MONTHLY;DTSTART=20160404T021000Z;COUNT=5;INTERVAL=2;WKST=MO;BYDAY=MO,TU ``` -##### Exclusion date +##### Inclusion date and Exclusion date ```swift +let rdateString = "RDATE:20180706T160000Z,20210706T160000Z" +if let inclusionDate = InclusionDate(rdateString: rdateString) { + print(inclusionDate.toRDateString()) + // RDATE:20180706T160000Z,20210706T160000Z + + print(inclusionDate.dates) + /* + 2018-07-07 00:00:00 Sun + 2021-07-07 00:00:00 Sun + */ +} + let exdateString = "EXDATE:20181231T160000Z,20201231T160000Z" if let exclusionDate = ExclusionDate(exdateString: exdateString, unitGranularity: .Year) { print(exclusionDate.toExDateString()) @@ -67,6 +80,7 @@ if let exclusionDate = ExclusionDate(exdateString: exdateString, unitGranularity let ruleString = "RRULE:FREQ=YEARLY;COUNT=11;WKST=MO" if let rule = RecurrenceRule(recurrenceWithRRuleString: ruleString) { var rule = rule + rule.rdate = inclusionDate // RDATE:20180706T160000Z,20210706T160000Z rule.exdate = exclusionDate // EXDATE:20181231T160000Z,20201231T160000Z let allDates = rule.allOccurrences() print(allDates) @@ -74,6 +88,7 @@ if let rule = RecurrenceRule(recurrenceWithRRuleString: ruleString) { 2016-04-14 14:22:30 Thu 2017-04-14 14:22:30 Fri 2018-04-14 14:22:30 Sat + 2018-07-07 00:00:00 Sat 2020-04-14 14:22:30 Tue 2022-04-14 14:22:30 Thu 2023-04-14 14:22:30 Fri @@ -82,12 +97,13 @@ if let rule = RecurrenceRule(recurrenceWithRRuleString: ruleString) { 2026-04-14 14:22:30 Tue */ - let date = dateFormatter.dateFromString("2017-01-01 00:00:00 Sun") - let otherDate = dateFormatter.dateFromString("2020-01-01 00:00:00 Wed") + let date = dateFormatter.dateFromString("2018-01-01 00:00:00 Sun") + let otherDate = dateFormatter.dateFromString("2024-01-01 00:00:00 Mon") let betweenDates = rule.occurrencesBetween(date: date!, andDate: otherDate!) print(betweenDates) /* 2018-04-14 14:22:30 Sat + 2018-07-07 00:00:00 Sat 2020-04-14 14:22:30 Tue 2022-04-14 14:22:30 Thu 2023-04-14 14:22:30 Fri diff --git a/RRuleSwift.xcodeproj/project.pbxproj b/RRuleSwift.xcodeproj/project.pbxproj index 9412bcc..213afee 100644 --- a/RRuleSwift.xcodeproj/project.pbxproj +++ b/RRuleSwift.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ D31B13BF1CAA7F1800D0B863 /* Generators.swift in Sources */ = {isa = PBXBuildFile; fileRef = D31B13BE1CAA7F1700D0B863 /* Generators.swift */; }; D382675C1CB4BCFB0080C91A /* NSDate+Comparison.swift in Sources */ = {isa = PBXBuildFile; fileRef = D382675B1CB4BCFB0080C91A /* NSDate+Comparison.swift */; }; D393D72F1CBF507700B89FB8 /* ExclusionDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D393D72E1CBF507700B89FB8 /* ExclusionDate.swift */; }; + D393D7311CBF79C800B89FB8 /* InclusionDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D393D7301CBF79C800B89FB8 /* InclusionDate.swift */; }; D3D7E3E51CB3E03F00BF052F /* nlp.js in Resources */ = {isa = PBXBuildFile; fileRef = D3D7E3E31CB3E03F00BF052F /* nlp.js */; }; D3D7E3E61CB3E03F00BF052F /* rrule.js in Resources */ = {isa = PBXBuildFile; fileRef = D3D7E3E41CB3E03F00BF052F /* rrule.js */; }; D3D7E3E81CB3EBC800BF052F /* JavaScriptBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3D7E3E71CB3EBC800BF052F /* JavaScriptBridge.swift */; }; @@ -29,6 +30,7 @@ D31B13BE1CAA7F1700D0B863 /* Generators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Generators.swift; sourceTree = ""; }; D382675B1CB4BCFB0080C91A /* NSDate+Comparison.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSDate+Comparison.swift"; sourceTree = ""; }; D393D72E1CBF507700B89FB8 /* ExclusionDate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExclusionDate.swift; sourceTree = ""; }; + D393D7301CBF79C800B89FB8 /* InclusionDate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InclusionDate.swift; sourceTree = ""; }; D3D7E3E31CB3E03F00BF052F /* nlp.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = nlp.js; sourceTree = ""; }; D3D7E3E41CB3E03F00BF052F /* rrule.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = rrule.js; sourceTree = ""; }; D3D7E3E71CB3EBC800BF052F /* JavaScriptBridge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JavaScriptBridge.swift; sourceTree = ""; }; @@ -67,6 +69,7 @@ children = ( D3D7E3E21CB3E03F00BF052F /* lib */, D31B13AD1CA90A9A00D0B863 /* RecurrenceRule.swift */, + D393D7301CBF79C800B89FB8 /* InclusionDate.swift */, D393D72E1CBF507700B89FB8 /* ExclusionDate.swift */, D31B13A91CA8F37F00D0B863 /* RRule.swift */, D31B13BE1CAA7F1700D0B863 /* Generators.swift */, @@ -180,6 +183,7 @@ D382675C1CB4BCFB0080C91A /* NSDate+Comparison.swift in Sources */, D31B13AE1CA90A9A00D0B863 /* RecurrenceRule.swift in Sources */, D3D7E3E81CB3EBC800BF052F /* JavaScriptBridge.swift in Sources */, + D393D7311CBF79C800B89FB8 /* InclusionDate.swift in Sources */, D31B13B01CA90ED300D0B863 /* RecurrenceFrequency.swift in Sources */, D393D72F1CBF507700B89FB8 /* ExclusionDate.swift in Sources */, D31B13BF1CAA7F1800D0B863 /* Generators.swift in Sources */, diff --git a/RRuleSwift/Generators.swift b/RRuleSwift/Generators.swift index 1f773e8..e4442c9 100644 --- a/RRuleSwift/Generators.swift +++ b/RRuleSwift/Generators.swift @@ -31,6 +31,10 @@ public extension RecurrenceRule { } var occurrences = allOccurrences + if let rdates = rdate?.dates { + occurrences.appendContentsOf(rdates) + } + if let exdates = exdate?.dates, unit = exdate?.unit { for occurrence in occurrences { for exdate in exdates { @@ -43,7 +47,7 @@ public extension RecurrenceRule { } } - return occurrences + return occurrences.sort { $0.isBeforeOrSameWith($1) } } public func occurrencesBetween(date date: NSDate, andDate otherDate: NSDate) -> [NSDate] { @@ -68,6 +72,10 @@ public extension RecurrenceRule { } var occurrences = betweenOccurrences + if let rdates = rdate?.dates { + occurrences.appendContentsOf(rdates) + } + if let exdates = exdate?.dates, unit = exdate?.unit { for occurrence in occurrences { for exdate in exdates { @@ -80,6 +88,6 @@ public extension RecurrenceRule { } } - return occurrences + return occurrences.sort { $0.isBeforeOrSameWith($1) } } } diff --git a/RRuleSwift/InclusionDate.swift b/RRuleSwift/InclusionDate.swift new file mode 100644 index 0000000..ee5c55e --- /dev/null +++ b/RRuleSwift/InclusionDate.swift @@ -0,0 +1,53 @@ +// +// InclusionDate.swift +// RRuleSwift +// +// Created by Xin Hong on 16/3/28. +// Copyright © 2016年 Teambition. All rights reserved. +// + +import Foundation + +public struct InclusionDate { + /// All inclusive dates. + public private(set) var dates = [NSDate]() + + public init(dates: [NSDate]) { + self.dates = dates + } + + public init?(rdateString string: String) { + let string = string.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()) + guard let range = string.rangeOfString("RDATE:") where range.startIndex == string.startIndex else { + print("error: invalid rdate string, must be started with 'RDATE:'") + return nil + } + let rdateString = string.substringFromIndex(range.endIndex) + let rdates = rdateString.componentsSeparatedByString(",").flatMap { (dateString) -> String? in + if (dateString.isEmpty || dateString.characters.count == 0) { + return nil + } + return dateString + } + + self.dates = rdates.flatMap({ (dateString) -> NSDate? in + return RRule.dateFormatter.dateFromString(dateString) + }) + } + + public func toRDateString() -> String { + var rdateString = "RDATE:" + let dateStrings = dates.map { (date) -> String in + return RRule.dateFormatter.stringFromDate(date) + } + if dateStrings.count > 0 { + rdateString += dateStrings.joinWithSeparator(",") + } + + if rdateString.substringFromIndex(rdateString.endIndex.advancedBy(-1)) == "," { + rdateString.removeAtIndex(rdateString.endIndex.advancedBy(-1)) + } + + return rdateString + } +} diff --git a/RRuleSwift/RecurrenceRule.swift b/RRuleSwift/RecurrenceRule.swift index 263b20b..b291d6d 100644 --- a/RRuleSwift/RecurrenceRule.swift +++ b/RRuleSwift/RecurrenceRule.swift @@ -71,7 +71,10 @@ public struct RecurrenceRule { /// The seconds of the minute associated with the recurrence rule, as an array of integers. public var bysecond = [Int]() - /// The exclusion dates of the recurrence rule. + /// The inclusive dates of the recurrence rule. + public var rdate: InclusionDate? + + /// The exclusion dates of the recurrence rule. The dates of this property will not be generated, even if some inclusive rdate matches the recurrence rule. public var exdate: ExclusionDate? public init(frequency: RecurrenceFrequency) { diff --git a/RRuleSwift/Supporting Files/Info.plist b/RRuleSwift/Supporting Files/Info.plist index 2a44702..2730238 100644 --- a/RRuleSwift/Supporting Files/Info.plist +++ b/RRuleSwift/Supporting Files/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 0.0.5 + 0.0.6 CFBundleSignature ???? CFBundleVersion diff --git a/RRuleSwiftExample/Info.plist b/RRuleSwiftExample/Info.plist index cd3eff8..492f5e4 100644 --- a/RRuleSwiftExample/Info.plist +++ b/RRuleSwiftExample/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.0.5 + 0.0.6 CFBundleSignature ???? CFBundleVersion - 5 + 6 LSRequiresIPhoneOS UILaunchStoryboardName diff --git a/RRuleSwiftExample/RRuleExample.playground/Contents.swift b/RRuleSwiftExample/RRuleExample.playground/Contents.swift index 697e8d6..f9c8621 100644 --- a/RRuleSwiftExample/RRuleExample.playground/Contents.swift +++ b/RRuleSwiftExample/RRuleExample.playground/Contents.swift @@ -19,11 +19,21 @@ if let rule1 = RecurrenceRule(recurrenceWithRRuleString: ruleString1) { }) } +let rdateString = "RDATE:20160701T023000Z,20120702T023000Z" +if let inclusionDate = InclusionDate(rdateString: rdateString) { + let rdates = inclusionDate.dates +} + let exdateString = "EXDATE:20160416T030000Z,20160420T030000Z" if let exclusionDate = ExclusionDate(exdateString: exdateString, unitGranularity: .Day) { let exdates = exclusionDate.dates } +let rdate1 = dateFormatter.dateFromString("2018-07-07 00:00:00 Sun")! +let rdate2 = dateFormatter.dateFromString("2021-07-07 00:00:00 Sun")! +let ruleInclusionDate = InclusionDate(dates: [rdate1, rdate2]) +let ruleRDateString = ruleInclusionDate.toRDateString() + let exdate1 = dateFormatter.dateFromString("2019-01-01 00:00:00 Sun")! let exdate2 = dateFormatter.dateFromString("2021-01-01 00:00:00 Wed")! let ruleExclusionDate = ExclusionDate(dates: [exdate1, exdate2], unitGranularity: .Year) @@ -34,12 +44,13 @@ let ruleString2 = "RRULE:FREQ=YEARLY;COUNT=11;WKST=MO" if let rule2 = RecurrenceRule(recurrenceWithRRuleString: ruleString2) { var rule2 = rule2 rule2.exdate = ruleExclusionDate + rule2.rdate = ruleInclusionDate let allDates = rule2.allOccurrences().map({ (date) -> String in return dateFormatter.stringFromDate(date) }) let date = dateFormatter.dateFromString("2018-01-01 00:00:00 Sun") - let otherDate = dateFormatter.dateFromString("2024-01-01 00:00:00 Wed") + let otherDate = dateFormatter.dateFromString("2024-01-01 00:00:00 Mon") let betweenDates = rule2.occurrencesBetween(date: date!, andDate: otherDate!).map({ (date) -> String in return dateFormatter.stringFromDate(date) }) diff --git a/RRuleSwiftExample/RRuleExample.playground/timeline.xctimeline b/RRuleSwiftExample/RRuleExample.playground/timeline.xctimeline index 1ac919a..dd7eebf 100644 --- a/RRuleSwiftExample/RRuleExample.playground/timeline.xctimeline +++ b/RRuleSwiftExample/RRuleExample.playground/timeline.xctimeline @@ -3,18 +3,18 @@ version = "3.0"> @@ -26,21 +26,33 @@ shouldTrackSuperviewWidth = "NO"> + + + +