Train status now properly gives minutes (or hours) a train is early or late

- Convert AmtrakDateFormatting API from static to instance properties/methods and added parsedDate(from:) to return Date.
- Update time(from:) and date(from:) to instance methods. Improve isOnTime logic to compute actual vs scheduled differences (minutes/hours) and report early/late/on-time.
- Updated ContentView to create an AmtrakDateFormatting instance and use the new API. Remove the Train.serviceDate extension.
This commit is contained in:
Tony Bark 2026-08-23 20:32:33 -04:00
parent 69fc10c6f2
commit 3533e5d4b8
2 changed files with 35 additions and 18 deletions

View file

@ -1,23 +1,32 @@
import Foundation import Foundation
struct AmtrakDateFormatting { struct AmtrakDateFormatting {
static let isoFormatter = ISO8601DateFormatter() let isoFormatter = ISO8601DateFormatter()
static let timeFormatter: DateFormatter = { let timeFormatter: DateFormatter = {
let formatter = DateFormatter() let formatter = DateFormatter()
formatter.dateStyle = .none formatter.dateStyle = .none
formatter.timeStyle = .short formatter.timeStyle = .short
return formatter return formatter
}() }()
static let dateFormatter: DateFormatter = { let dateFormatter: DateFormatter = {
let formatter = DateFormatter() let formatter = DateFormatter()
formatter.dateStyle = .medium formatter.dateStyle = .medium
formatter.timeStyle = .none formatter.timeStyle = .none
return formatter return formatter
}() }()
static func time(from isoString: String?) -> String? { func parsedDate(from isoString: String?) -> Date? {
guard let isoString, !isoString.isEmpty, let date = isoFormatter.date(
from: isoString) else {
return nil
}
return isoFormatter.date(from: isoString)
}
func time(from isoString: String?) -> String? {
guard let isoString, !isoString.isEmpty, let date = isoFormatter.date( guard let isoString, !isoString.isEmpty, let date = isoFormatter.date(
from: isoString) else { from: isoString) else {
return nil return nil
@ -26,7 +35,7 @@ struct AmtrakDateFormatting {
return timeFormatter.string(from: date) return timeFormatter.string(from: date)
} }
static func date(from isoString: String?) -> String? { func date(from isoString: String?) -> String? {
guard let isoString, !isoString.isEmpty, let date = isoFormatter.date( guard let isoString, !isoString.isEmpty, let date = isoFormatter.date(
from: isoString) else { from: isoString) else {
return nil return nil

View file

@ -1,11 +1,6 @@
import SwiftCrossUI import SwiftCrossUI
import Foundation import Foundation
extension Train {
var serviceDate: String {
AmtrakDateFormatting.date(from: createdAt) ?? "-"
}
}
struct ContentView: View { struct ContentView: View {
@State var client = AmtrakClient() @State var client = AmtrakClient()
@ -137,23 +132,36 @@ struct ContentView: View {
func isOnTime(arr: String?, schArr: String?) -> String { func isOnTime(arr: String?, schArr: String?) -> String {
let amtrakDate = AmtrakDateFormatting() let amtrakDate = AmtrakDateFormatting()
if AmtrakDateFormatting guard
.time(from: arr) != AmtrakDateFormatting let actualDate = amtrakDate.parsedDate(from: arr),
.time(from: schArr) { let scheduledDate = amtrakDate.parsedDate(from: schArr)
return "Late" else {
return "On Time"
} }
return "On Time" let differenceInMinutes = Int(actualDate.timeIntervalSince(scheduledDate) / 60)
switch differenceInMinutes {
case -1...1:
return "On Time"
case ..<0:
return "\(-differenceInMinutes) min early"
case 0..<60:
return "\(differenceInMinutes) min late"
default:
let hours = differenceInMinutes / 60
return "\(hours) hr late"
}
} }
func trainStatus(for train: Train, atStationCode code: String) -> TrainStatusRow { func trainStatus(for train: Train, atStationCode code: String) -> TrainStatusRow {
let leg = train.stations?.first { $0.code == code } let leg = train.stations?.first { $0.code == code }
let platform = leg?.platform ?? "-" let amtrakDate = AmtrakDateFormatting()
let stationName = leg?.name ?? unknown let stationName = leg?.name ?? unknown
let arrival = AmtrakDateFormatting.time(from: leg?.arr) ?? AmtrakDateFormatting.time( let arrival = amtrakDate.time(from: leg?.arr) ?? amtrakDate.time(
from: leg?.schArr from: leg?.schArr
) )
let depature = AmtrakDateFormatting.time(from: leg?.dep) ?? AmtrakDateFormatting.time( let depature = amtrakDate.time(from: leg?.dep) ?? amtrakDate.time(
from: leg?.schDep from: leg?.schDep
) )