Skip to content

Instantly share code, notes, and snippets.

@adriansergheev
Created September 1, 2025 09:54
Show Gist options
  • Select an option

  • Save adriansergheev/363183110715efc79ec2a214d1e62cca to your computer and use it in GitHub Desktop.

Select an option

Save adriansergheev/363183110715efc79ec2a214d1e62cca to your computer and use it in GitHub Desktop.
timezone-charts
import SwiftUI
import Charts
struct FacilityResponse: Codable {
let id: String
let name: String
let timeZone: String
let hasConsumption: Bool
let hasProduction: Bool
let measurements: Measurements
}
struct Measurements: Codable {
let timeZone: String
let messages: [String]
let data: [MeasurementData]
}
struct MeasurementData: Codable {
let timestamp: String
let spotPrice: SpotPrice?
let consumption: Consumption?
let production: Production?
}
struct SpotPrice: Codable {
let unit: String
let value: Double
}
struct Consumption: Codable {
}
struct Production: Codable {
let unit: String
let total: Double
let sold: Double?
let consumed: Double?
}
class ChartModel: ObservableObject {
@Published var chartData: [ChartDataPoint] = []
private let stockholmTimeZone = TimeZone(identifier: "Europe/Stockholm")!
struct ChartDataPoint: Identifiable {
let id = UUID()
let date: Date
// let displayDate: String
let production: Double
let spotPrice: Double?
}
func loadData(from json: Data) {
let decoder = JSONDecoder()
do {
let facilities = try decoder.decode([FacilityResponse].self, from: json)
guard let facility = facilities.first else { return }
let dateFormatter = ISO8601DateFormatter()
let displayFormatter = DateFormatter()
displayFormatter.timeZone = stockholmTimeZone
displayFormatter.dateFormat = "MMM d"
chartData = facility.measurements.data.compactMap { measurement in
guard let date = dateFormatter.date(from: measurement.timestamp) else {
fatalError()
}
return ChartDataPoint(
date: date,
production: measurement.production?.total ?? 0,
spotPrice: measurement.spotPrice?.value
)
}
} catch {
print("Error decoding JSON: \(error)")
}
}
}
struct ProductionChartView: View {
@StateObject private var viewModel = ChartModel()
@State var selectedDate: Bool = true
var body: some View {
VStack(alignment: .leading, spacing: 20) {
Text("Solar Production - Stockholm Time")
.font(.title2)
.bold()
Chart(viewModel.chartData) { dataPoint in
BarMark(
x: .value("Date", dataPoint.date),
y: .value("Production", dataPoint.production)
)
.foregroundStyle(.green.gradient)
if let spotPrice = dataPoint.spotPrice {
LineMark(
x: .value("Date", dataPoint.date),
y: .value("Spot Price", spotPrice / 10)
)
.foregroundStyle(.orange)
.lineStyle(StrokeStyle(lineWidth: 2))
.symbol(.circle)
}
}
.frame(height: 300)
.chartXScale(
domain: .automatic(dataType: Date.self) { dates in
dates
}
)
.chartYAxis {
AxisMarks(position: .leading) { value in
AxisValueLabel {
if let production = value.as(Double.self) {
Text("\(Int(production)) kWh")
.font(.caption)
}
}
AxisGridLine()
}
}
// .chartScrollPosition(x: $selectedDate)
// .onChange(of: $selectedDate) { date in
//
// }
.chartYAxis {
AxisMarks(position: .trailing) { value in
AxisValueLabel {
if let price = value.as(Double.self) {
Text("\(Int(price * 10)) öre")
.font(.caption)
.foregroundColor(.orange)
}
}
}
}
.chartLegend {
HStack(spacing: 20) {
Label("Production (kWh)", systemImage: "square.fill")
.foregroundColor(.green)
Label("Spot Price (öre)", systemImage: "line.diagonal")
.foregroundColor(.orange)
}
.font(.caption)
}
// Display timezone info
HStack {
Image(systemName: "clock")
Text("All times shown in Europe/Stockholm timezone")
.font(.caption)
.foregroundColor(.secondary)
}
}
.padding()
.onAppear {
// Load your JSON data here
if let jsonData = sampleJSON.data(using: .utf8) {
viewModel.loadData(from: jsonData)
}
}
}
}
// Sample JSON for testing
let sampleJSON = """
[
{
"id": "225d0085-b260-48c7-8d0e-0fc539e8aabd",
"name": "Odonbacken 6",
"timeZone": "Europe/Stockholm",
"hasConsumption": false,
"hasProduction": true,
"measurements": {
"timeZone": "Europe/Stockholm",
"messages": [],
"data": [
{
"timestamp": "2025-08-24T22:00:00Z",
"spotPrice": {
"unit": "öre",
"value": 60.03554
},
"consumption": null,
"production": {
"unit": "kWh",
"total": 23.37,
"sold": null,
"consumed": null
}
},
{
"timestamp": "2025-08-25T22:00:00Z",
"spotPrice": {
"unit": "öre",
"value": 104.656296
},
"consumption": null,
"production": {
"unit": "kWh",
"total": 30.28,
"sold": null,
"consumed": null
}
}
]
}
}
]
"""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment