├── README.md
├── .gitignore
├── Tests
├── LinuxMain.swift
└── ACNHEventsTests
│ ├── XCTestManifests.swift
│ └── ACNHEventsTests.swift
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── Package.swift
└── Sources
└── ACNHEvents
└── Date+ACNHEvents.swift
/README.md:
--------------------------------------------------------------------------------
1 | # ACNHEvents
2 |
3 | A description of this package.
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 | xcuserdata/
6 |
--------------------------------------------------------------------------------
/Tests/LinuxMain.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | import ACNHEventsTests
4 |
5 | var tests = [XCTestCaseEntry]()
6 | tests += ACNHEventsTests.allTests()
7 | XCTMain(tests)
8 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Tests/ACNHEventsTests/XCTestManifests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | #if !canImport(ObjectiveC)
4 | public func allTests() -> [XCTestCaseEntry] {
5 | return [
6 | testCase(ACNHEventsTests.allTests),
7 | ]
8 | }
9 | #endif
10 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.2
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "ACNHEvents",
8 | products: [
9 | // Products define the executables and libraries produced by a package, and make them visible to other packages.
10 | .library(
11 | name: "ACNHEvents",
12 | targets: ["ACNHEvents"]),
13 | ],
14 | dependencies: [
15 | // Dependencies declare other packages that this package depends on.
16 | // .package(url: /* package url */, from: "1.0.0"),
17 | ],
18 | targets: [
19 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
20 | // Targets can depend on other targets in this package, and on products in packages which this package depends on.
21 | .target(
22 | name: "ACNHEvents",
23 | dependencies: []),
24 | .testTarget(
25 | name: "ACNHEventsTests",
26 | dependencies: ["ACNHEvents"]),
27 | ]
28 | )
29 |
--------------------------------------------------------------------------------
/Sources/ACNHEvents/Date+ACNHEvents.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public enum Hemisphere {
4 | case north, south
5 | }
6 |
7 | public enum Event {
8 | // 1.0.0 - 1.1.4
9 | case bunnyDay, fishingTourney, earthDay, newYearsDay, newYearsEve, cherryBlossumSeason, bugOff
10 | // 1.2.0
11 | case natureDay, mayDay, museumDay, weddingSeason
12 | }
13 |
14 | public extension Date {
15 | func events(for hemisphere: Hemisphere) -> [Event] {
16 | var events: [Event] = []
17 |
18 | // v1.0.0 - 1.1.4
19 | if isBunnyDay { events.append(.bunnyDay) }
20 | if isFishingTourneyDay { events.append(.fishingTourney) }
21 | if isEarthDay { events.append(.earthDay) }
22 | if isNewYearsDay { events.append(.newYearsDay) }
23 | if isNewYearsEve { events.append(.newYearsEve) }
24 | if isCherryBlossomSeason(hemisphere) { events.append(.cherryBlossumSeason) }
25 | if isBugOffDay(hemisphere) { events.append(.bugOff) }
26 |
27 | // v1.2.0
28 | if isNatureDay { events.append(.natureDay) }
29 | if isMayDay { events.append(.mayDay) }
30 | if isMuseumDay { events.append(.museumDay) }
31 | if isWeddingSeason { events.append(.weddingSeason) }
32 |
33 | return events
34 | }
35 |
36 | var isBunnyDay: Bool {
37 | let components = Calendar.current.dateComponents([.day, .month], from: self)
38 |
39 | guard let month = components.month, let day = components.day else {
40 | return false
41 | }
42 |
43 | return month == 4 && day >= 1 && day <= 12
44 | }
45 |
46 | var isNatureDay: Bool {
47 | let components = Calendar.current.dateComponents([.day, .month], from: self)
48 |
49 | guard let month = components.month, let day = components.day else {
50 | return false
51 | }
52 |
53 | return (month == 4 && day >= 23 && day <= 31) || (month == 5 && day <= 4)
54 | }
55 |
56 | var isMayDay: Bool {
57 | let components = Calendar.current.dateComponents([.day, .month], from: self)
58 |
59 | guard let month = components.month, let day = components.day else {
60 | return false
61 | }
62 |
63 | return month == 5 && day >= 1 && day <= 7
64 | }
65 |
66 | var isMuseumDay: Bool {
67 | let components = Calendar.current.dateComponents([.day, .month], from: self)
68 |
69 | guard let month = components.month, let day = components.day else {
70 | return false
71 | }
72 |
73 | return month == 5 && day >= 18 && day <= 31
74 | }
75 |
76 | var isWeddingSeason: Bool {
77 | let components = Calendar.current.dateComponents([.day, .month], from: self)
78 |
79 | guard let month = components.month, let day = components.day else {
80 | return false
81 | }
82 |
83 | return month == 6 && day >= 1 && day <= 30
84 | }
85 |
86 | var isFishingTourneyDay: Bool {
87 | let components = Calendar.current.dateComponents([.day, .month, .weekday], from: self)
88 |
89 | guard let month = components.month, let day = components.day else {
90 | return false
91 | }
92 |
93 | switch month {
94 | case 1, 4, 7, 10:
95 | return components.weekday == 7 && (day - 1) / 7 == 1
96 | default:
97 | return false
98 | }
99 | }
100 |
101 | var isEarthDay: Bool {
102 | let components = Calendar.current.dateComponents([.day, .month], from: self)
103 |
104 | guard let month = components.month, let day = components.day else {
105 | return false
106 | }
107 |
108 | return month == 4 && day == 22
109 | }
110 |
111 | var isNewYearsDay: Bool {
112 | let components = Calendar.current.dateComponents([.day, .month], from: self)
113 |
114 | guard let month = components.month, let day = components.day else {
115 | return false
116 | }
117 |
118 | return month == 1 && day == 1
119 | }
120 |
121 | var isNewYearsEve: Bool {
122 | let components = Calendar.current.dateComponents([.day, .month], from: self)
123 |
124 | guard let month = components.month, let day = components.day else {
125 | return false
126 | }
127 |
128 | return month == 12 && day == 31
129 | }
130 |
131 | func isCherryBlossomSeason(_ hemisphere: Hemisphere) -> Bool {
132 | let components = Calendar.current.dateComponents([.day, .month], from: self)
133 |
134 | guard let month = components.month, let day = components.day else {
135 | return false
136 | }
137 |
138 | let inDayRange = (day >= 1 && day <= 10)
139 |
140 | switch hemisphere {
141 | case .north:
142 | return month == 4 && inDayRange
143 | case .south:
144 | return month == 10 && inDayRange
145 | }
146 | }
147 |
148 | func isBugOffDay(_ hemisphere: Hemisphere) -> Bool {
149 | let components = Calendar.current.dateComponents([.day, .month, .weekday], from: self)
150 |
151 | guard let month = components.month, let day = components.day else {
152 | return false
153 | }
154 |
155 | switch hemisphere {
156 | case .north:
157 | switch month {
158 | case 6, 7, 8, 9:
159 | return components.weekday == 7 && (day - 1) / 7 == 3
160 | default:
161 | return false
162 | }
163 | case .south:
164 | switch month {
165 | case 1, 2, 11, 12:
166 | return components.weekday == 7 && (day - 1) / 7 == 2
167 | default:
168 | return false
169 | }
170 | }
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/Tests/ACNHEventsTests/ACNHEventsTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import ACNHEvents
3 |
4 | final class ACNHEventsTests: XCTestCase {
5 |
6 | func testEarthDay() {
7 | let c = DateComponents(calendar: .current, month: 4, day: 22)
8 | let d = Calendar.current.date(from: c)
9 | XCTAssertEqual(d?.isEarthDay, true)
10 | }
11 |
12 | func testNewYearDay() {
13 | let c = DateComponents(calendar: .current, month: 1, day: 1)
14 | let d = Calendar.current.date(from: c)
15 | XCTAssertEqual(d?.isNewYearsDay, true)
16 | }
17 |
18 | func testNewYearEve() {
19 | let c = DateComponents(calendar: .current, month: 12, day: 31)
20 | let d = Calendar.current.date(from: c)
21 | XCTAssertEqual(d?.isNewYearsEve, true)
22 | }
23 |
24 | func testSpringFishTourney() {
25 | let c = DateComponents(calendar: .current, year: 2020, month: 4, day: 11)
26 | let d = Calendar.current.date(from: c)
27 | XCTAssertEqual(d?.isFishingTourneyDay, true)
28 | }
29 |
30 | func testSummerFishTourney() {
31 | let c = DateComponents(calendar: .current, year: 2020, month: 7, day: 11)
32 | let d = Calendar.current.date(from: c)
33 | XCTAssertEqual(d?.isFishingTourneyDay, true)
34 | }
35 |
36 | func testFallFishTourney() {
37 | let c = DateComponents(calendar: .current, year: 2020, month: 10, day: 10)
38 | let d = Calendar.current.date(from: c)
39 | XCTAssertEqual(d?.isFishingTourneyDay, true)
40 | }
41 |
42 | func testWinterFishTourney() {
43 | let c = DateComponents(calendar: .current, year: 2020, month: 1, day: 11)
44 | let d = Calendar.current.date(from: c)
45 | XCTAssertEqual(d?.isFishingTourneyDay, true)
46 | }
47 |
48 | func testNorthCherryBlossomSeason() {
49 | let c = DateComponents(calendar: .current, year: 2020, month: 4, day: 1)
50 | let d = Calendar.current.date(from: c)
51 | XCTAssertEqual(d?.isCherryBlossomSeason(.north), true)
52 |
53 | let c1 = DateComponents(calendar: .current, year: 2020, month: 4, day: 10)
54 | let d1 = Calendar.current.date(from: c1)
55 | XCTAssertEqual(d1?.isCherryBlossomSeason(.north), true)
56 |
57 | let c2 = DateComponents(calendar: .current, year: 2020, month: 4, day: 11)
58 | let d2 = Calendar.current.date(from: c2)
59 | XCTAssertEqual(d2?.isCherryBlossomSeason(.north), false)
60 | }
61 |
62 | func testSouthCherryBlossomSeason() {
63 | let c = DateComponents(calendar: .current, year: 2020, month: 10, day: 1)
64 | let d = Calendar.current.date(from: c)
65 | XCTAssertEqual(d?.isCherryBlossomSeason(.south), true)
66 |
67 | let c1 = DateComponents(calendar: .current, year: 2020, month: 10, day: 10)
68 | let d1 = Calendar.current.date(from: c1)
69 | XCTAssertEqual(d1?.isCherryBlossomSeason(.south), true)
70 |
71 | let c2 = DateComponents(calendar: .current, year: 2020, month: 10, day: 11)
72 | let d2 = Calendar.current.date(from: c2)
73 | XCTAssertEqual(d2?.isCherryBlossomSeason(.south), false)
74 | }
75 |
76 | func testBunnyDay() {
77 | let c = DateComponents(calendar: .current, year: 2020, month: 4, day: 1)
78 | let d = Calendar.current.date(from: c)
79 | XCTAssertEqual(d?.isBunnyDay, true)
80 |
81 | let c1 = DateComponents(calendar: .current, year: 2020, month: 4, day: 12)
82 | let d1 = Calendar.current.date(from: c1)
83 | XCTAssertEqual(d1?.isBunnyDay, true)
84 |
85 | let c2 = DateComponents(calendar: .current, year: 2020, month: 4, day: 13)
86 | let d2 = Calendar.current.date(from: c2)
87 | XCTAssertEqual(d2?.isBunnyDay, false)
88 | }
89 |
90 | func testNorthBugDayOffs() {
91 | let c = DateComponents(calendar: .current, year: 2020, month: 6, day: 27)
92 | let d = Calendar.current.date(from: c)
93 | XCTAssertEqual(d?.isBugOffDay(.north), true)
94 |
95 | let c1 = DateComponents(calendar: .current, year: 2020, month: 7, day: 25)
96 | let d1 = Calendar.current.date(from: c1)
97 | XCTAssertEqual(d1?.isBugOffDay(.north), true)
98 |
99 | let c2 = DateComponents(calendar: .current, year: 2020, month: 8, day: 22)
100 | let d2 = Calendar.current.date(from: c2)
101 | XCTAssertEqual(d2?.isBugOffDay(.north), true)
102 |
103 | let c3 = DateComponents(calendar: .current, year: 2020, month: 9, day: 26)
104 | let d3 = Calendar.current.date(from: c3)
105 | XCTAssertEqual(d3?.isBugOffDay(.north), true)
106 | }
107 |
108 | func testSouthBugDayOffs() {
109 | let c = DateComponents(calendar: .current, year: 2020, month: 11, day: 21)
110 | let d = Calendar.current.date(from: c)
111 | XCTAssertEqual(d?.isBugOffDay(.south), true)
112 |
113 | let c1 = DateComponents(calendar: .current, year: 2020, month: 12, day: 19)
114 | let d1 = Calendar.current.date(from: c1)
115 | XCTAssertEqual(d1?.isBugOffDay(.south), true)
116 |
117 | let c2 = DateComponents(calendar: .current, year: 2020, month: 1, day: 18)
118 | let d2 = Calendar.current.date(from: c2)
119 | XCTAssertEqual(d2?.isBugOffDay(.south), true)
120 |
121 | let c3 = DateComponents(calendar: .current, year: 2020, month: 2, day: 15)
122 | let d3 = Calendar.current.date(from: c3)
123 | XCTAssertEqual(d3?.isBugOffDay(.south), true)
124 | }
125 |
126 | static var allTests = [
127 | ("testEarthDay", testEarthDay),
128 | ("testNewYearDay", testNewYearDay),
129 | ("testNewYearEve", testNewYearEve),
130 | ("testSpringFishTourney", testSpringFishTourney),
131 | ("testSummerFishTourney", testSummerFishTourney),
132 | ("testFallFishTourney", testFallFishTourney),
133 | ("testWinterFishTourney", testWinterFishTourney),
134 | ("testNorthCherryBlossomSeason", testNorthCherryBlossomSeason),
135 | ("testSouthCherryBlossomSeason", testSouthCherryBlossomSeason),
136 | ("testBunnyDay", testBunnyDay),
137 | ("testNorthBugDayOffs", testNorthBugDayOffs),
138 | ("testSouthBugDayOffs", testSouthBugDayOffs),
139 | ]
140 | }
141 |
--------------------------------------------------------------------------------