Skip to content

Commit 8c7a068

Browse files
Allow timezone override (#525)
1 parent 849eb69 commit 8c7a068

4 files changed

Lines changed: 51 additions & 1 deletion

File tree

LoopFollow/Controllers/Graphs.swift

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,16 @@ extension MainViewController {
721721
func createMidnightLines() {
722722
// Draw a line at midnight: useful when showing multiple days of data
723723
if Storage.shared.showMidnightLines.value {
724-
var midnightTimeInterval = dateTimeUtils.getTimeIntervalMidnightToday()
724+
var midnightTimeInterval: TimeInterval
725+
if Storage.shared.graphTimeZoneEnabled.value,
726+
let tz = TimeZone(identifier: Storage.shared.graphTimeZoneIdentifier.value)
727+
{
728+
var cal = Calendar.current
729+
cal.timeZone = tz
730+
midnightTimeInterval = cal.startOfDay(for: Date()).timeIntervalSince1970
731+
} else {
732+
midnightTimeInterval = dateTimeUtils.getTimeIntervalMidnightToday()
733+
}
725734
let graphHours = 24 * Storage.shared.downloadDays.value
726735
let graphStart = dateTimeUtils.getTimeIntervalNHoursAgo(N: graphHours)
727736
while midnightTimeInterval > graphStart {
@@ -1881,6 +1890,12 @@ extension MainViewController {
18811890
dateFormatter.setLocalizedDateFormatFromTemplate("hh:mm")
18821891
}
18831892

1893+
if Storage.shared.graphTimeZoneEnabled.value,
1894+
let tz = TimeZone(identifier: Storage.shared.graphTimeZoneIdentifier.value)
1895+
{
1896+
dateFormatter.timeZone = tz
1897+
}
1898+
18841899
let wrappedLine1 = wrapText(line1, maxLineLength: 40)
18851900

18861901
let date = Date(timeIntervalSince1970: time)

LoopFollow/Helpers/Chart.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ final class ChartXValueFormatter: AxisValueFormatter {
2828
dateFormatter.setLocalizedDateFormatFromTemplate("hh:mm")
2929
}
3030

31+
if Storage.shared.graphTimeZoneEnabled.value,
32+
let tz = TimeZone(identifier: Storage.shared.graphTimeZoneIdentifier.value)
33+
{
34+
dateFormatter.timeZone = tz
35+
}
36+
3137
// let date = Date(timeIntervalSince1970: epochTimezoneOffset)
3238
let date = Date(timeIntervalSince1970: value)
3339
let formattedDate = dateFormatter.string(from: date)

LoopFollow/Settings/GraphSettingsView.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ struct GraphSettingsView: View {
1313
@ObservedObject private var show90MinLine = Storage.shared.show90MinLine
1414
@ObservedObject private var showMidnightLines = Storage.shared.showMidnightLines
1515
@ObservedObject private var smallGraphTreatments = Storage.shared.smallGraphTreatments
16+
@ObservedObject private var graphTimeZoneEnabled = Storage.shared.graphTimeZoneEnabled
17+
@ObservedObject private var graphTimeZoneIdentifier = Storage.shared.graphTimeZoneIdentifier
1618

1719
@ObservedObject private var smallGraphHeight = Storage.shared.smallGraphHeight
1820
@ObservedObject private var predictionToLoad = Storage.shared.predictionToLoad
@@ -48,6 +50,18 @@ struct GraphSettingsView: View {
4850

4951
Toggle("Show Midnight Lines", isOn: $showMidnightLines.value)
5052
.onChange(of: showMidnightLines.value) { _ in markDirty() }
53+
54+
Toggle("Time Zone Override", isOn: $graphTimeZoneEnabled.value)
55+
.onChange(of: graphTimeZoneEnabled.value) { _ in markDirty() }
56+
57+
if graphTimeZoneEnabled.value {
58+
Picker("Time Zone", selection: $graphTimeZoneIdentifier.value) {
59+
ForEach(Self.sortedTimeZones, id: \.identifier) { tz in
60+
Text(Self.timeZoneLabel(tz)).tag(tz.identifier)
61+
}
62+
}
63+
.onChange(of: graphTimeZoneIdentifier.value) { _ in markDirty() }
64+
}
5165
}
5266

5367
// ── Treatments ───────────────────────────────────────────────
@@ -140,4 +154,17 @@ struct GraphSettingsView: View {
140154
private func markDirty() {
141155
Observable.shared.chartSettingsChanged.value = true
142156
}
157+
158+
// MARK: - Time Zone Helpers
159+
160+
private static let sortedTimeZones: [TimeZone] = TimeZone.knownTimeZoneIdentifiers
161+
.compactMap { TimeZone(identifier: $0) }
162+
.sorted { $0.secondsFromGMT() < $1.secondsFromGMT() }
163+
164+
private static func timeZoneLabel(_ tz: TimeZone) -> String {
165+
let offsetMinutes = tz.secondsFromGMT() / 60
166+
let sign = offsetMinutes >= 0 ? "+" : "-"
167+
let offsetString = String(format: "UTC%@%02d:%02d", sign, abs(offsetMinutes) / 60, abs(offsetMinutes) % 60)
168+
return "(\(offsetString)) \(tz.identifier)"
169+
}
143170
}

LoopFollow/Storage/Storage.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ class Storage {
9898
var lowLine = StorageValue<Double>(key: "lowLine", defaultValue: 70.0)
9999
var highLine = StorageValue<Double>(key: "highLine", defaultValue: 180.0)
100100
var downloadDays = StorageValue<Int>(key: "downloadDays", defaultValue: 1)
101+
var graphTimeZoneEnabled = StorageValue<Bool>(key: "graphTimeZoneEnabled", defaultValue: false)
102+
var graphTimeZoneIdentifier = StorageValue<String>(key: "graphTimeZoneIdentifier", defaultValue: TimeZone.current.identifier)
101103
// Graph Settings [END]
102104

103105
// Calendar entries [BEGIN]

0 commit comments

Comments
 (0)