GameDate from the provider is used for getting odds data #430

Closed
opened 2026-08-25 16:39:30 +02:00 by johnsturgeon · 0 comments
Owner

Tank01 gameDate is a join key, not a derivable date

Source: Tank01's author, direct conversation, August 2026. Confirmed against
payload data the same day.

The fact

gameDate on /getNFLGamesForWeek (format "20250904") exists because
consumers read the feed from every time zone. Its value is the date that maps to
the gameDate parameter of /getNFLBettingOdds — it is the provider's
correlation key between the two endpoints, not a general-purpose calendar date.

Its timezone is US Eastern, and that is the provider's business, not ours.

Why it cannot be derived from gameTime_epoch

Deriving it looks safe — the epoch is right there in the same row — and it is
wrong for every primetime game. Converting epoch to a UTC date rolls past
midnight for any kickoff after 8pm ET:

game gameDate UTC date ET date
20250904_DAL@PHI 20250904 20250905 20250904
20250905_KC@LAC 20250905 20250906 20250905
20250907_BAL@BUF 20250907 20250908 20250907
20250908_MIN@CHI 20250908 20250909 20250908

That is Thursday night, Sunday night and Monday night — every marquee slot.

The failure is silent. A wrong gameDate returns an empty odds result rather
than an error, which yields no line for exactly the games most people care
about: no spread, no favorite, and a pick page that looks broken for reasons
nothing logged.

Re-verify any time:

from datetime import datetime, timezone
from zoneinfo import ZoneInfo

epoch, game_date = 1757031600.0, "20250904"       # DAL@PHI, 8:20p ET opener
utc = datetime.fromtimestamp(epoch, tz=timezone.utc)
assert utc.strftime("%Y%m%d") != game_date        # UTC is a day ahead
assert utc.astimezone(ZoneInfo("America/New_York")).strftime("%Y%m%d") == game_date

Rules that follow

  1. Carry gameDate in the provider DTO. It is a documented cross-endpoint
    contract, which makes it one of the sturdiest fields to model — not the
    redundant-looking field it appears to be next to gameTime_epoch.
  2. Pass it through opaquely. Never reconstruct it, never reformat it, never
    parse it into a date and back.
  3. Do not let it past the client. It is a transport detail. Pool-side code
    gets start_time (a real UTC datetime derived from gameTime_epoch), which
    is what any pool logic should reason about. gameDate answers "which odds
    call does this game belong to" and nothing else.

Rule 3 already holds: game_date does not appear anywhere outside
app/tank01_api/.

# Tank01 `gameDate` is a join key, not a derivable date **Source:** Tank01's author, direct conversation, August 2026. Confirmed against payload data the same day. ## The fact `gameDate` on `/getNFLGamesForWeek` (format `"20250904"`) exists because consumers read the feed from every time zone. Its value is the date that maps to the `gameDate` **parameter of `/getNFLBettingOdds`** — it is the provider's correlation key between the two endpoints, not a general-purpose calendar date. Its timezone is US Eastern, and that is the provider's business, not ours. ## Why it cannot be derived from `gameTime_epoch` Deriving it looks safe — the epoch is right there in the same row — and it is wrong for every primetime game. Converting epoch to a UTC date rolls past midnight for any kickoff after 8pm ET: | game | `gameDate` | UTC date | ET date | |---|---|---|---| | `20250904_DAL@PHI` | 20250904 | 2025**0905** | 20250904 | | `20250905_KC@LAC` | 20250905 | 2025**0906** | 20250905 | | `20250907_BAL@BUF` | 20250907 | 2025**0908** | 20250907 | | `20250908_MIN@CHI` | 20250908 | 2025**0909** | 20250908 | That is Thursday night, Sunday night and Monday night — every marquee slot. The failure is silent. A wrong `gameDate` returns an empty odds result rather than an error, which yields no line for exactly the games most people care about: no spread, no favorite, and a pick page that looks broken for reasons nothing logged. Re-verify any time: ```python from datetime import datetime, timezone from zoneinfo import ZoneInfo epoch, game_date = 1757031600.0, "20250904" # DAL@PHI, 8:20p ET opener utc = datetime.fromtimestamp(epoch, tz=timezone.utc) assert utc.strftime("%Y%m%d") != game_date # UTC is a day ahead assert utc.astimezone(ZoneInfo("America/New_York")).strftime("%Y%m%d") == game_date ``` ## Rules that follow 1. **Carry `gameDate` in the provider DTO.** It is a documented cross-endpoint contract, which makes it one of the sturdiest fields to model — not the redundant-looking field it appears to be next to `gameTime_epoch`. 2. **Pass it through opaquely.** Never reconstruct it, never reformat it, never parse it into a date and back. 3. **Do not let it past the client.** It is a transport detail. Pool-side code gets `start_time` (a real UTC datetime derived from `gameTime_epoch`), which is what any pool logic should reason about. `gameDate` answers "which odds call does this game belong to" and nothing else. Rule 3 already holds: `game_date` does not appear anywhere outside `app/tank01_api/`.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
johnsturgeon/tgfp-web#430
No description provided.