Add polyfill for Calender's `nextDate` method on linux
Remove autoupdatingCurrent, it's unavailable on linux
This commit is contained in:
parent
db5109b042
commit
5daabf3701
|
@ -21,6 +21,8 @@
|
|||
/* End PBXAggregateTarget section */
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
62AA63022133970A00A442A5 /* Calendar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62AA63012133970A00A442A5 /* Calendar.swift */; };
|
||||
62AA63042133A0FB00A442A5 /* CalendarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62AA63032133A0FB00A442A5 /* CalendarTests.swift */; };
|
||||
667D2DF72132C5390071DC89 /* DeinitObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 667D2DF62132C5390071DC89 /* DeinitObserver.swift */; };
|
||||
667D2DF92132C95D0071DC89 /* DeinitObserverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 667D2DF82132C95D0071DC89 /* DeinitObserverTests.swift */; };
|
||||
OBJ_45 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* Atomic.swift */; };
|
||||
|
@ -69,6 +71,8 @@
|
|||
|
||||
/* Begin PBXFileReference section */
|
||||
626D761B2113F9D100FCAFFE /* README.zh_cn.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.zh_cn.md; sourceTree = "<group>"; };
|
||||
62AA63012133970A00A442A5 /* Calendar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Calendar.swift; sourceTree = "<group>"; };
|
||||
62AA63032133A0FB00A442A5 /* CalendarTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarTests.swift; sourceTree = "<group>"; };
|
||||
667D2DF62132C5390071DC89 /* DeinitObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeinitObserver.swift; sourceTree = "<group>"; };
|
||||
667D2DF82132C95D0071DC89 /* DeinitObserverTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeinitObserverTests.swift; sourceTree = "<group>"; };
|
||||
668685ED210DCC0E009305C3 /* .swift-version */ = {isa = PBXFileReference; lastKnownFileType = text; path = ".swift-version"; sourceTree = "<group>"; };
|
||||
|
@ -125,6 +129,15 @@
|
|||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
62AA6300213396CE00A442A5 /* Platforms */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
667D2DF62132C5390071DC89 /* DeinitObserver.swift */,
|
||||
62AA63012133970A00A442A5 /* Calendar.swift */,
|
||||
);
|
||||
name = Platforms;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
668685EC210DCBD4009305C3 /* Related */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -146,7 +159,6 @@
|
|||
OBJ_10 /* Bucket.swift */,
|
||||
OBJ_11 /* Extensions.swift */,
|
||||
OBJ_13 /* Lock.swift */,
|
||||
667D2DF62132C5390071DC89 /* DeinitObserver.swift */,
|
||||
);
|
||||
name = Utils;
|
||||
sourceTree = "<group>";
|
||||
|
@ -168,8 +180,9 @@
|
|||
children = (
|
||||
OBJ_26 /* AtomicTests.swift */,
|
||||
OBJ_27 /* BucketTests.swift */,
|
||||
OBJ_29 /* ExtensionsTests.swift */,
|
||||
62AA63032133A0FB00A442A5 /* CalendarTests.swift */,
|
||||
667D2DF82132C95D0071DC89 /* DeinitObserverTests.swift */,
|
||||
OBJ_29 /* ExtensionsTests.swift */,
|
||||
);
|
||||
name = UtilsTests;
|
||||
sourceTree = "<group>";
|
||||
|
@ -235,6 +248,7 @@
|
|||
OBJ_19 /* TaskHub.swift */,
|
||||
OBJ_21 /* Timeline.swift */,
|
||||
668685F5210DD226009305C3 /* DateTime */,
|
||||
62AA6300213396CE00A442A5 /* Platforms */,
|
||||
668685F4210DD21A009305C3 /* Utils */,
|
||||
);
|
||||
name = Schedule;
|
||||
|
@ -345,6 +359,7 @@
|
|||
OBJ_45 /* Atomic.swift in Sources */,
|
||||
OBJ_46 /* Bucket.swift in Sources */,
|
||||
OBJ_47 /* Extensions.swift in Sources */,
|
||||
62AA63022133970A00A442A5 /* Calendar.swift in Sources */,
|
||||
OBJ_48 /* Interval.swift in Sources */,
|
||||
OBJ_49 /* Lock.swift in Sources */,
|
||||
OBJ_50 /* Monthday.swift in Sources */,
|
||||
|
@ -372,6 +387,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 0;
|
||||
files = (
|
||||
62AA63042133A0FB00A442A5 /* CalendarTests.swift in Sources */,
|
||||
OBJ_77 /* AtomicTests.swift in Sources */,
|
||||
OBJ_78 /* BucketTests.swift in Sources */,
|
||||
OBJ_79 /* DateTimeTests.swift in Sources */,
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
//
|
||||
// Calendar.swift
|
||||
// Schedule
|
||||
//
|
||||
// Created by Quentin MED on 2018/8/27.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Calendar {
|
||||
|
||||
func next(_ weekday: Weekday, after date: Date = Date()) -> Date? {
|
||||
let components = weekday.toDateComponents()
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
|
||||
return nextDate(after: date, matching: components, matchingPolicy: .strict)
|
||||
|
||||
#elseif os(Linux)
|
||||
|
||||
var c = dateComponents(in: .current, from: date)
|
||||
var days = components.weekday! - c.weekday!
|
||||
if days <= 0 {
|
||||
days += 7
|
||||
}
|
||||
return self.date(byAdding: .day, value: days, to: date)?.zeroClock()
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
func next(_ monthday: Monthday, after date: Date = Date()) -> Date? {
|
||||
let components = monthday.toDateComponents()
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
|
||||
return nextDate(after: date, matching: components, matchingPolicy: .strict)
|
||||
|
||||
#elseif os(Linux)
|
||||
|
||||
var old = dateComponents(in: .current, from: date)
|
||||
var new = DateComponents(calendar: self, timeZone: .current)
|
||||
new.year = old.year
|
||||
new.month = components.month
|
||||
new.day = components.day
|
||||
if components.month! < old.month! {
|
||||
new.year! += 1
|
||||
} else if components.month! == old.month! {
|
||||
if components.day! <= old.day! {
|
||||
new.year! += 1
|
||||
}
|
||||
}
|
||||
return self.date(from: new)
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -36,7 +36,7 @@ extension Date {
|
|||
|
||||
func zeroClock() -> Date {
|
||||
let calendar = Calendar.gregorian
|
||||
let timeZone = TimeZone.autoupdatingCurrent
|
||||
let timeZone = TimeZone.current
|
||||
var dateComponents = calendar.dateComponents(in: timeZone, from: self)
|
||||
dateComponents.hour = 0
|
||||
dateComponents.minute = 0
|
||||
|
|
|
@ -35,7 +35,7 @@ public enum Monthday {
|
|||
case december(Int)
|
||||
|
||||
var isToday: Bool {
|
||||
let lhs = Calendar.gregorian.dateComponents(in: TimeZone.autoupdatingCurrent, from: Date())
|
||||
let lhs = Calendar.gregorian.dateComponents(in: TimeZone.current, from: Date())
|
||||
let rhs = toDateComponents()
|
||||
return lhs.month == rhs.month && lhs.day == rhs.day
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ public enum Monthday {
|
|||
case .december(let n): month = 12; day = n
|
||||
}
|
||||
return DateComponents(calendar: Calendar.gregorian,
|
||||
timeZone: TimeZone.autoupdatingCurrent,
|
||||
timeZone: TimeZone.current,
|
||||
month: month,
|
||||
day: day)
|
||||
}
|
||||
|
|
|
@ -386,13 +386,12 @@ extension Schedule {
|
|||
public static func every(_ weekday: Weekday) -> DateMiddleware {
|
||||
let schedule = Schedule.make { () -> AnyIterator<Date> in
|
||||
let calendar = Calendar.gregorian
|
||||
let components = weekday.toDateComponents()
|
||||
var date: Date!
|
||||
return AnyIterator<Date> {
|
||||
if weekday.isToday {
|
||||
date = Date().zeroClock()
|
||||
} else if date == nil {
|
||||
date = calendar.nextDate(after: Date(), matching: components, matchingPolicy: .strict)
|
||||
date = calendar.next(weekday, after: Date())
|
||||
} else {
|
||||
date = calendar.date(byAdding: .day, value: 7, to: date)
|
||||
}
|
||||
|
@ -414,16 +413,15 @@ extension Schedule {
|
|||
}
|
||||
|
||||
/// Creates a schedule that executes the task every specific day in the month.
|
||||
public static func every(_ monthDay: Monthday) -> DateMiddleware {
|
||||
public static func every(_ monthday: Monthday) -> DateMiddleware {
|
||||
let schedule = Schedule.make { () -> AnyIterator<Date> in
|
||||
let calendar = Calendar.gregorian
|
||||
let components = monthDay.toDateComponents()
|
||||
var date: Date!
|
||||
return AnyIterator<Date> {
|
||||
if monthDay.isToday {
|
||||
if monthday.isToday {
|
||||
date = Date().zeroClock()
|
||||
} else if date == nil {
|
||||
date = calendar.nextDate(after: Date(), matching: components, matchingPolicy: .strict)
|
||||
date = calendar.next(monthday, after: Date())
|
||||
} else {
|
||||
date = calendar.date(byAdding: .year, value: 1, to: date)
|
||||
}
|
||||
|
|
|
@ -93,12 +93,12 @@ public struct Time {
|
|||
formatter = DateFormatter()
|
||||
formatter?.locale = Locale(identifier: "en_US_POSIX")
|
||||
formatter?.calendar = Calendar.gregorian
|
||||
formatter?.timeZone = TimeZone.autoupdatingCurrent
|
||||
formatter?.timeZone = TimeZone.current
|
||||
formatter.dateFormat = fmt
|
||||
}
|
||||
if let date = formatter.date(from: string) {
|
||||
Time.FormatterCache.setObject(formatter, forKey: NSString(string: fmt))
|
||||
let components = Calendar.gregorian.dateComponents(in: TimeZone.autoupdatingCurrent, from: date)
|
||||
let components = Calendar.gregorian.dateComponents(in: TimeZone.current, from: date)
|
||||
if let hour = components.hour,
|
||||
let minute = components.minute,
|
||||
let second = components.second,
|
||||
|
@ -119,7 +119,7 @@ public struct Time {
|
|||
|
||||
func toDateComponents() -> DateComponents {
|
||||
return DateComponents(calendar: Calendar.gregorian,
|
||||
timeZone: TimeZone.autoupdatingCurrent,
|
||||
timeZone: TimeZone.current,
|
||||
hour: hour, minute: minute,
|
||||
second: second, nanosecond: nanosecond)
|
||||
}
|
||||
|
|
|
@ -14,12 +14,12 @@ public enum Weekday: Int {
|
|||
|
||||
var isToday: Bool {
|
||||
return Calendar.gregorian
|
||||
.dateComponents(in: .autoupdatingCurrent, from: Date()).weekday == rawValue
|
||||
.dateComponents(in: .current, from: Date()).weekday == rawValue
|
||||
}
|
||||
|
||||
func toDateComponents() -> DateComponents {
|
||||
return DateComponents(calendar: Calendar.gregorian,
|
||||
timeZone: TimeZone.autoupdatingCurrent,
|
||||
timeZone: TimeZone.current,
|
||||
weekday: rawValue)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// CalendarTests.swift
|
||||
// ScheduleTests
|
||||
//
|
||||
// Created by Quentin MED on 2018/8/27.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Schedule
|
||||
|
||||
final class CalendarTests: XCTestCase {
|
||||
|
||||
func testNextWeekday() {
|
||||
|
||||
let date = Date(year: 2018, month: 8, day: 1, hour: 6)
|
||||
|
||||
let n0 = Calendar.gregorian.next(.monday, after: date)
|
||||
XCTAssertEqual(n0?.dateComponents.year, 2018)
|
||||
XCTAssertEqual(n0?.dateComponents.month, 8)
|
||||
XCTAssertEqual(n0?.dateComponents.day, 6)
|
||||
XCTAssertEqual(n0?.dateComponents.weekday, 2)
|
||||
|
||||
let n1 = Calendar.gregorian.next(.friday, after: date)
|
||||
XCTAssertEqual(n1?.dateComponents.year, 2018)
|
||||
XCTAssertEqual(n1?.dateComponents.month, 8)
|
||||
XCTAssertEqual(n1?.dateComponents.day, 3)
|
||||
XCTAssertEqual(n1?.dateComponents.weekday, 6)
|
||||
}
|
||||
|
||||
func testNextMonthday() {
|
||||
|
||||
let date = Date(year: 2000, month: 4, day: 1, hour: 6)
|
||||
|
||||
let n0 = Calendar.gregorian.next(.april(1), after: date)
|
||||
XCTAssertEqual(n0?.dateComponents.year, 2001)
|
||||
XCTAssertEqual(n0?.dateComponents.month, 4)
|
||||
XCTAssertEqual(n0?.dateComponents.day, 1)
|
||||
|
||||
let n1 = Calendar.gregorian.next(.october(10), after: date)
|
||||
XCTAssertEqual(n1?.dateComponents.year, 2000)
|
||||
XCTAssertEqual(n1?.dateComponents.month, 10)
|
||||
XCTAssertEqual(n1?.dateComponents.day, 10)
|
||||
}
|
||||
|
||||
static var allTests = [
|
||||
("testNextWeekday", testNextWeekday),
|
||||
("testNextMonthday", testNextMonthday)
|
||||
]
|
||||
}
|
|
@ -8,6 +8,8 @@
|
|||
import XCTest
|
||||
@testable import Schedule
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
|
||||
final class DeinitObserverTests: XCTestCase {
|
||||
|
||||
func testObserver() {
|
||||
|
@ -26,3 +28,5 @@ final class DeinitObserverTests: XCTestCase {
|
|||
("testObserver", testObserver)
|
||||
]
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,19 +11,19 @@ import Foundation
|
|||
extension Date {
|
||||
|
||||
var dateComponents: DateComponents {
|
||||
return Calendar.gregorian.dateComponents(in: TimeZone.autoupdatingCurrent, from: self)
|
||||
return Calendar.gregorian.dateComponents(in: TimeZone.current, from: self)
|
||||
}
|
||||
|
||||
var localizedDescription: String {
|
||||
let formatter = DateFormatter()
|
||||
formatter.timeZone = TimeZone.autoupdatingCurrent
|
||||
formatter.timeZone = TimeZone.current
|
||||
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
|
||||
return formatter.string(from: self)
|
||||
}
|
||||
|
||||
init(year: Int, month: Int, day: Int, hour: Int = 0, minute: Int = 0, second: Int = 0, nanosecond: Int = 0) {
|
||||
let components = DateComponents(calendar: Calendar.gregorian,
|
||||
timeZone: TimeZone.autoupdatingCurrent,
|
||||
timeZone: TimeZone.current,
|
||||
year: year, month: month, day: day,
|
||||
hour: hour, minute: minute, second: second,
|
||||
nanosecond: nanosecond)
|
||||
|
|
|
@ -11,13 +11,13 @@ import XCTest
|
|||
final class TaskTests: XCTestCase {
|
||||
|
||||
func testSchedule() {
|
||||
let expectation = XCTestExpectation(description: "testSchedule")
|
||||
let e = expectation(description: "testSchedule")
|
||||
let date = Date()
|
||||
let task = Schedule.after(0.5.second).do {
|
||||
XCTAssertTrue(Date().timeIntervalSince(date).isAlmostEqual(to: 0.5, leeway: 0.1))
|
||||
expectation.fulfill()
|
||||
e.fulfill()
|
||||
}
|
||||
wait(for: [expectation], timeout: 2)
|
||||
waitForExpectations(timeout: 2)
|
||||
task.cancel()
|
||||
}
|
||||
|
||||
|
@ -46,15 +46,15 @@ final class TaskTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testAddAndRemoveActions() {
|
||||
let expectation = XCTestExpectation(description: "testAddAndRemoveActions")
|
||||
let e = expectation(description: "testAddAndRemoveActions")
|
||||
let task = Schedule.after(0.5.second).do { }
|
||||
let date = Date()
|
||||
let key = task.addAction { _ in
|
||||
XCTAssertTrue(Date().timeIntervalSince(date).isAlmostEqual(to: 0.5, leeway: 0.1))
|
||||
expectation.fulfill()
|
||||
e.fulfill()
|
||||
}
|
||||
XCTAssertEqual(task.countOfActions, 2)
|
||||
wait(for: [expectation], timeout: 2)
|
||||
waitForExpectations(timeout: 2)
|
||||
task.removeAction(byKey: key)
|
||||
XCTAssertEqual(task.countOfActions, 1)
|
||||
task.cancel()
|
||||
|
@ -65,25 +65,28 @@ final class TaskTests: XCTestCase {
|
|||
|
||||
func testAddAndRemoveTags() {
|
||||
let task = Schedule.never.do { }
|
||||
task.addTag("c")
|
||||
task.addTags("n", "s", "z")
|
||||
XCTAssertTrue(task.tags.contains("c"))
|
||||
XCTAssertTrue(task.tags.contains("z"))
|
||||
task.removeTag("c")
|
||||
XCTAssertFalse(task.tags.contains("c"))
|
||||
task.removeTags("s", "z")
|
||||
XCTAssertFalse(task.tags.contains("s"))
|
||||
XCTAssertFalse(task.tags.contains("z"))
|
||||
let tagA = UUID().uuidString
|
||||
let tagB = UUID().uuidString
|
||||
let tagC = UUID().uuidString
|
||||
task.addTag(tagA)
|
||||
task.addTags(tagB, tagC)
|
||||
XCTAssertTrue(task.tags.contains(tagA))
|
||||
XCTAssertTrue(task.tags.contains(tagC))
|
||||
task.removeTag(tagA)
|
||||
XCTAssertFalse(task.tags.contains(tagA))
|
||||
task.removeTags(tagB, tagC)
|
||||
XCTAssertFalse(task.tags.contains(tagB))
|
||||
XCTAssertFalse(task.tags.contains(tagC))
|
||||
task.cancel()
|
||||
}
|
||||
|
||||
func testReschedule() {
|
||||
let expectation = XCTestExpectation(description: "testReschedule")
|
||||
let e = expectation(description: "testReschedule")
|
||||
var i = 0
|
||||
let task = Schedule.after(0.1.second).do { (task) in
|
||||
i += 1
|
||||
if task.countOfExecution == 6 && task.timeline.estimatedNextExecution == nil {
|
||||
expectation.fulfill()
|
||||
e.fulfill()
|
||||
}
|
||||
if task.countOfExecution > 6 {
|
||||
XCTFail("should never come here")
|
||||
|
@ -92,11 +95,12 @@ final class TaskTests: XCTestCase {
|
|||
DispatchQueue.global().async(after: 0.5.second) {
|
||||
task.reschedule(Schedule.every(0.1.second).first(5))
|
||||
}
|
||||
wait(for: [expectation], timeout: 2)
|
||||
waitForExpectations(timeout: 2)
|
||||
task.cancel()
|
||||
}
|
||||
|
||||
func testParasiticTask() {
|
||||
let e = expectation(description: "testParasiticTask")
|
||||
let fn = {
|
||||
let obj = NSObject()
|
||||
Schedule.after(0.5.second).do(host: obj, onElapse: {
|
||||
|
@ -104,11 +108,14 @@ final class TaskTests: XCTestCase {
|
|||
})
|
||||
}
|
||||
fn()
|
||||
wait(for: [], timeout: 1)
|
||||
DispatchQueue.main.async(after: 0.75.seconds) {
|
||||
e.fulfill()
|
||||
}
|
||||
waitForExpectations(timeout: 1)
|
||||
}
|
||||
|
||||
func testLifetime() {
|
||||
let expectation = XCTestExpectation(description: "testLifetime")
|
||||
let e = expectation(description: "testLifetime")
|
||||
let task = Schedule.after(1.hour).do { }
|
||||
task.setLifetime(1.second)
|
||||
XCTAssertEqual(task.lifetime, 1.second)
|
||||
|
@ -122,9 +129,9 @@ final class TaskTests: XCTestCase {
|
|||
}
|
||||
DispatchQueue.global().async(after: 2.second) {
|
||||
XCTAssertTrue(task.isCancelled)
|
||||
expectation.fulfill()
|
||||
e.fulfill()
|
||||
}
|
||||
wait(for: [expectation], timeout: 5)
|
||||
waitForExpectations(timeout: 5)
|
||||
}
|
||||
|
||||
static var allTests = [
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import XCTest
|
||||
|
||||
#if !os(macOS)
|
||||
#if os(Linux)
|
||||
public func allTests() -> [XCTestCaseEntry] {
|
||||
return [
|
||||
testCase(DateTimeTests.allTests),
|
||||
|
@ -9,6 +9,7 @@ public func allTests() -> [XCTestCaseEntry] {
|
|||
testCase(TaskTests.allTests),
|
||||
testCase(AtomicTests.allTests),
|
||||
testCase(BucketTests.allTests),
|
||||
testCase(CalendarTests.allTests),
|
||||
testCase(ExtensionsTests.allTests)
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue