summaryrefslogtreecommitdiffstats
path: root/Shared/Models/SolsticeData.swift
blob: d891a0aa43185df093232a598f209a36960ba568 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import Foundation

class SolsticeData {
    static let shared = SolsticeData()

    private let events: [SolsticeEvent]

    private init() {
        let table: [(year: Int, month: Int, day: Int, hour: Int, minute: Int, season: Season)] = [
            // 2025
            (2025,  3, 20,  9,  1, .spring),
            (2025,  6, 20, 14, 42, .summer),
            (2025,  9, 22, 18, 20, .autumn),
            (2025, 12, 21, 15,  3, .winter),
            // 2026
            (2026,  3, 20, 14, 46, .spring),
            (2026,  6, 21,  8, 25, .summer),
            (2026,  9, 23,  0,  6, .autumn),
            (2026, 12, 21, 20, 50, .winter),
            // 2027
            (2027,  3, 20, 20, 25, .spring),
            (2027,  6, 21, 14, 11, .summer),
            (2027,  9, 23,  6,  2, .autumn),
            (2027, 12, 22,  2, 43, .winter),
            // 2028
            (2028,  3, 20,  2, 17, .spring),
            (2028,  6, 20, 20,  2, .summer),
            (2028,  9, 22, 11, 45, .autumn),
            (2028, 12, 21,  8, 20, .winter),
            // 2029
            (2029,  3, 20,  8,  1, .spring),
            (2029,  6, 21,  1, 48, .summer),
            (2029,  9, 22, 17, 37, .autumn),
            (2029, 12, 21, 14, 14, .winter),
            // 2030
            (2030,  3, 20, 13, 51, .spring),
            (2030,  6, 21,  7, 31, .summer),
            (2030,  9, 22, 23, 27, .autumn),
            (2030, 12, 21, 20,  9, .winter),
        ]

        events = table
            .map { row in
                SolsticeEvent(
                    date: SolsticeData.dateFromUTC(year: row.year, month: row.month, day: row.day,
                                                   hour: row.hour, minute: row.minute),
                    season: row.season
                )
            }
            .sorted { $0.date < $1.date }
    }

    private static func dateFromUTC(year: Int, month: Int, day: Int, hour: Int, minute: Int) -> Date {
        var components = DateComponents()
        components.year = year
        components.month = month
        components.day = day
        components.hour = hour
        components.minute = minute
        components.second = 0
        components.timeZone = TimeZone(abbreviation: "UTC")
        return Calendar(identifier: .gregorian).date(from: components) ?? Date()
    }

    func nextEvent(from now: Date = Date()) -> SolsticeEvent? {
        return events.first(where: { $0.date > now })
    }

    func currentEvent(from now: Date = Date()) -> SolsticeEvent? {
        guard let nextIndex = events.firstIndex(where: { $0.date > now }),
              nextIndex > 0 else { return nil }
        return events[nextIndex - 1]
    }

    func upcomingEvents(count: Int, from now: Date = Date()) -> [SolsticeEvent] {
        let futureEvents = events.filter { $0.date > now }
        return Array(futureEvents.prefix(count))
    }

    func progressToNextEvent(from now: Date = Date()) -> (elapsed: Int, total: Int)? {
        guard let nextIndex = events.firstIndex(where: { $0.date > now }),
              nextIndex > 0 else { return nil }

        let today = Calendar.current.startOfDay(for: now)
        let previousEventDay = Calendar.current.startOfDay(for: events[nextIndex - 1].date)
        let eventDay = Calendar.current.startOfDay(for: events[nextIndex].date)

        let elapsed = max(0, Calendar.current.dateComponents([.day], from: previousEventDay, to: today).day ?? 0)
        let total   = max(1, Calendar.current.dateComponents([.day], from: previousEventDay, to: eventDay).day ?? 1)

        return (elapsed: elapsed, total: total)
    }
}