APIHorseRacing

Documentation / Guides

Timezones and dates

Everything is UTC except a race time, which is local to the course.

One rule, and one exception to it. The exception is the single most common integration mistake in racing data, so it is worth thirty seconds now.

The rule

Every timestamp is UTC, in ISO 8601, with an explicit offset.

"data_as_of":   "2026-09-09T08:50:32+00:00"
"published_at": "2026-09-08T19:04:11+00:00"
"delivered_at": "2026-09-09T14:22:07+00:00"

The exception

race_time is local to the course, and carries no offset.

"race_time": "14:35"

A 14:35 at Musselburgh and a 14:35 at Meydan are both the time on the racecourse clock. That is what a racecard prints, what a commentator says and what your users expect to see. Converting it to UTC would mean showing a British user 13:35 for a race everyone else calls the 2.35, which is wrong in the way that matters.

So do not parse race_time as a timestamp, and do not apply an offset to it. It is a label, and it belongs next to the course name that gives it meaning.

Dates are plain

date on a race or a meeting is YYYY-MM-DD with no time and no zone. It is the raceday as the jurisdiction defines it. An evening meeting that finishes after midnight local time still belongs to the day it started.

Every date parameter takes the same format. Anything else returns invalid_param rather than being guessed at, because guessing between 03/04 and 04/03 is how a backfill silently loads the wrong year.

Why this combination

Racing spans twelve jurisdictions across most of the world's time zones. Two things follow.

  • Anything we generate is UTC, so ordering, comparison and storage all work without knowing where anything happened.
  • Anything the sport prints stays as printed, because a racecard time is a cultural object rather than an instant. Reformatting it helps nobody.

If you need a real instant for a race

You need three things: the date, the local time, and the course's zone. We give you the first two and the course. We deliberately do not give you the third, because getting it right requires per-course zone data including historical daylight saving rules, and a wrong answer is worse than no answer.

If your product genuinely needs it, map course to zone yourself from a maintained database and combine. Most products do not: they show the local time beside the course, which is what the sport does.

Practical notes

  • Sort by date then race_time as strings. Both formats sort lexicographically, so it works without parsing.
  • Do not compare race_time across courses to decide which race is next. Two tracks in different countries at the same clock time are hours apart.
  • Your window is evaluated in UTC. Around midnight UTC a free key's seven-day boundary moves, which can make a date readable one minute and not the next. That is the window doing its job.