GTFS stop_times.txt: arrival_time goes past 24:00:00 and strptime refuses it

Checked 2026-09-08 · Health, environment and transport datasets

GTFS times are counted from noon minus twelve hours of the service day, not clock times, so a trip that runs after midnight keeps counting: 24:01:00, 25:14:00, 26:57:00. In the current MBTA feed 217,407 of 4,494,139 stop_times rows — 4.84 percent — have an hour of 24 or more, and datetime.strptime with %H:%M:%S raises ValueError on every one of them. Parse the field as three integers and add the hours to the service date; do not treat it as a time of day.

What we saw

217,407 of 4,494,139 rows have an arrival hour of 24 or more; the largest is 26:57:00. Source (stop_times.txt, arrival_time, 2026-09-08).

rows: 4494139 arrival_time hour>=24: 217407 (4.84%) max: 26:57:00
hours >=24 histogram: [24, 25, 26] {24: 148584, 25: 61926, 26: 6897}

The affected rows are ordinary consecutive stops on ordinary trips, not a few bad records. Source (stop_times.txt, first three rows with hour >= 24, 2026-09-08).

{'trip_id': '76132147', 'arrival_time': '24:01:00', 'departure_time': '24:01:00', 'stop_id': '70264', 'stop_sequence': '7'}
{'trip_id': '76132147', 'arrival_time': '24:02:00', 'departure_time': '24:02:00', 'stop_id': '70261', 'stop_sequence': '8'}
{'trip_id': '76132148', 'arrival_time': '24:03:00', 'departure_time': '24:03:00', 'stop_id': '70261', 'stop_sequence': '1'}

9,796 of 168,145 trips have at least one stop past 24:00, so dropping the bad rows silently truncates one trip in seventeen. Source (stop_times.txt, distinct trip_id, 2026-09-08).

trips with any >=24:00 stop: 9796 of 168145

The standard parser refuses the value outright. Source (datetime.strptime with %H:%M:%S, 2026-09-08).

strptime ValueError: time data '26:57:00' does not match format '%H:%M:%S'

The feed under test is the current published one and identifies itself in feed_info.txt. Source (feed_info.txt, 2026-09-08).

feed_publisher_name,feed_publisher_url,feed_lang,feed_start_date,feed_end_date,feed_version,feed_contact_email,feed_id
MBTA,http://www.mbta.com,EN,20260830,20261212,"Fall 2026, 2026-09-06T00:56:24+00:00, version D",developer@mbta.com,mbta-ma-us

The command

curl -sSL -o mbta.zip -w 'http=%{http_code} bytes=%{size_download}\n' 'https://cdn.mbta.com/MBTA_GTFS.zip'
gtfs http=200 bytes=34398324 t=0.561817

Checked 2026-09-08.

python3 -c "
import zipfile,csv,io,collections
z=zipfile.ZipFile('mbta.zip'); n=over=0; mx='00:00:00'; hours=collections.Counter()
for row in csv.DictReader(io.TextIOWrapper(z.open('stop_times.txt'),'utf-8-sig')):
    n+=1; a=row['arrival_time']
    if not a: continue
    h=int(a.split(':')[0]); hours[h]+=1
    if h>=24: over+=1; mx=max(mx,a)
print(n, over, round(100*over/n,2), mx, {k:hours[k] for k in sorted(hours) if k>=24})"
rows: 4494139 arrival_time hour>=24: 217407 (4.84%) max: 26:57:00
hours >=24 histogram: [24, 25, 26] {24: 148584, 25: 61926, 26: 6897}

Checked 2026-09-08.

python3 -c "from datetime import datetime; datetime.strptime('26:57:00','%H:%M:%S')"
strptime ValueError: time data '26:57:00' does not match format '%H:%M:%S'

Checked 2026-09-08.

arrival hourrowsshare of 4,494,139
241485843.31%
25619261.38%
2668970.15%
24 or more, total2174074.84%

Limits

Open question

The hours here stop at 26. Is there a value above which feeds in practice never go, or is 24:00 simply the point past which nothing is guaranteed?

Plain text