feat: add timezone support for stadium-local game times

Adds timeZoneIdentifier to Stadium model and localGameTime/localGameTimeShort
computed properties to RichGame. Game times can now display in venue local
timezone. Also adds timezone field to Python StadiumInfo dataclass with
example entries for Pacific, Central, Mountain, and Toronto timezones.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-01-12 18:58:35 -06:00
parent 402a8877f3
commit 64c64093c4
3 changed files with 30 additions and 6 deletions

View File

@@ -42,6 +42,7 @@ class StadiumInfo:
sport: str
latitude: float
longitude: float
timezone: str = "America/New_York" # IANA timezone identifier
# Hardcoded stadium mappings
@@ -55,10 +56,10 @@ STADIUM_MAPPINGS: dict[str, dict[str, StadiumInfo]] = {
"stadium_nba_united_center": StadiumInfo("stadium_nba_united_center", "United Center", "Chicago", "IL", "USA", "nba", 41.8807, -87.6742),
"stadium_nba_rocket_mortgage_fieldhouse": StadiumInfo("stadium_nba_rocket_mortgage_fieldhouse", "Rocket Mortgage FieldHouse", "Cleveland", "OH", "USA", "nba", 41.4965, -81.6882),
"stadium_nba_american_airlines_center": StadiumInfo("stadium_nba_american_airlines_center", "American Airlines Center", "Dallas", "TX", "USA", "nba", 32.7905, -96.8103),
"stadium_nba_ball_arena": StadiumInfo("stadium_nba_ball_arena", "Ball Arena", "Denver", "CO", "USA", "nba", 39.7487, -105.0077),
"stadium_nba_ball_arena": StadiumInfo("stadium_nba_ball_arena", "Ball Arena", "Denver", "CO", "USA", "nba", 39.7487, -105.0077, "America/Denver"),
"stadium_nba_little_caesars_arena": StadiumInfo("stadium_nba_little_caesars_arena", "Little Caesars Arena", "Detroit", "MI", "USA", "nba", 42.3411, -83.0553),
"stadium_nba_chase_center": StadiumInfo("stadium_nba_chase_center", "Chase Center", "San Francisco", "CA", "USA", "nba", 37.7680, -122.3877),
"stadium_nba_toyota_center": StadiumInfo("stadium_nba_toyota_center", "Toyota Center", "Houston", "TX", "USA", "nba", 29.7508, -95.3621),
"stadium_nba_chase_center": StadiumInfo("stadium_nba_chase_center", "Chase Center", "San Francisco", "CA", "USA", "nba", 37.7680, -122.3877, "America/Los_Angeles"),
"stadium_nba_toyota_center": StadiumInfo("stadium_nba_toyota_center", "Toyota Center", "Houston", "TX", "USA", "nba", 29.7508, -95.3621, "America/Chicago"),
"stadium_nba_gainbridge_fieldhouse": StadiumInfo("stadium_nba_gainbridge_fieldhouse", "Gainbridge Fieldhouse", "Indianapolis", "IN", "USA", "nba", 39.7640, -86.1555),
"stadium_nba_intuit_dome": StadiumInfo("stadium_nba_intuit_dome", "Intuit Dome", "Inglewood", "CA", "USA", "nba", 33.9425, -118.3417),
"stadium_nba_cryptocom_arena": StadiumInfo("stadium_nba_cryptocom_arena", "Crypto.com Arena", "Los Angeles", "CA", "USA", "nba", 34.0430, -118.2673),
@@ -75,8 +76,8 @@ STADIUM_MAPPINGS: dict[str, dict[str, StadiumInfo]] = {
"stadium_nba_moda_center": StadiumInfo("stadium_nba_moda_center", "Moda Center", "Portland", "OR", "USA", "nba", 45.5316, -122.6668),
"stadium_nba_golden_1_center": StadiumInfo("stadium_nba_golden_1_center", "Golden 1 Center", "Sacramento", "CA", "USA", "nba", 38.5802, -121.4997),
"stadium_nba_frost_bank_center": StadiumInfo("stadium_nba_frost_bank_center", "Frost Bank Center", "San Antonio", "TX", "USA", "nba", 29.4270, -98.4375),
"stadium_nba_scotiabank_arena": StadiumInfo("stadium_nba_scotiabank_arena", "Scotiabank Arena", "Toronto", "ON", "Canada", "nba", 43.6435, -79.3791),
"stadium_nba_delta_center": StadiumInfo("stadium_nba_delta_center", "Delta Center", "Salt Lake City", "UT", "USA", "nba", 40.7683, -111.9011),
"stadium_nba_scotiabank_arena": StadiumInfo("stadium_nba_scotiabank_arena", "Scotiabank Arena", "Toronto", "ON", "Canada", "nba", 43.6435, -79.3791, "America/Toronto"),
"stadium_nba_delta_center": StadiumInfo("stadium_nba_delta_center", "Delta Center", "Salt Lake City", "UT", "USA", "nba", 40.7683, -111.9011, "America/Denver"),
"stadium_nba_capital_one_arena": StadiumInfo("stadium_nba_capital_one_arena", "Capital One Arena", "Washington", "DC", "USA", "nba", 38.8981, -77.0209),
},
"mlb": {

View File

@@ -91,4 +91,20 @@ struct RichGame: Identifiable, Hashable, Codable {
var venueDescription: String {
"\(stadium.name), \(stadium.city)"
}
/// Game time formatted in the stadium's local timezone with timezone indicator
var localGameTime: String {
let formatter = DateFormatter()
formatter.dateFormat = "h:mm a z"
formatter.timeZone = stadium.timeZone ?? .current
return formatter.string(from: game.dateTime)
}
/// Game time formatted in the stadium's local timezone without timezone indicator
var localGameTimeShort: String {
let formatter = DateFormatter()
formatter.dateFormat = "h:mm a"
formatter.timeZone = stadium.timeZone ?? .current
return formatter.string(from: game.dateTime)
}
}

View File

@@ -17,6 +17,7 @@ struct Stadium: Identifiable, Codable, Hashable {
let sport: Sport
let yearOpened: Int?
let imageURL: URL?
let timeZoneIdentifier: String?
init(
id: String,
@@ -28,7 +29,8 @@ struct Stadium: Identifiable, Codable, Hashable {
capacity: Int,
sport: Sport,
yearOpened: Int? = nil,
imageURL: URL? = nil
imageURL: URL? = nil,
timeZoneIdentifier: String? = nil
) {
self.id = id
self.name = name
@@ -40,6 +42,11 @@ struct Stadium: Identifiable, Codable, Hashable {
self.sport = sport
self.yearOpened = yearOpened
self.imageURL = imageURL
self.timeZoneIdentifier = timeZoneIdentifier
}
var timeZone: TimeZone? {
timeZoneIdentifier.flatMap { TimeZone(identifier: $0) }
}
var location: CLLocation {