Repository navigation
Conversation
Between midnight and the end of the night service, the buses that were actually running vanished from the station board - and the ETA arithmetic came out ~24 h out. A GTFS service day is not a calendar day. It starts at 00:00 and can run past midnight: a trip published at "25:10" departs at 01:10 the next morning and belongs to the PREVIOUS calendar date's service day. Feeds that run night services publish exactly that - the Cluj feed's 25N / 5N / 54N lines use 24:00-25:33. The app resolved "what is running now" against the calendar date, so during the post-midnight window the service day in progress was the wrong one and the still-running night buses were dropped from the board at exactly the moment they started running. The same class of error made every ETA computed against a schedule time from the other timeline read ~24 h out. New module src/lib/domain/pipeline/serviceDay.ts is the single place that answers "which service days are in progress, and where do their trip times land". Between local midnight and the rollover hour (04:00, the convention already assumed in config.ts) two service days are in progress at once, so the station board, the reconciler's active-trip set, the map view, the favourites "active routes" set and the schedule grid all query both of them and shift the previous day's times by -1440 onto the shared timeline. "Now" itself stays where it was - minutes since local midnight - so every other consumer is unaffected. The live side needed one more thing: a GTFS-RT observation carries the trip's service date, and for a night trip that is the previous date, so the orphan ETA seed now uses it instead of assuming the observation belongs to the current service day. Also fixes the station board wiping the ETA the reconciler had already seeded onto an orphan row. tests/night-routes.spec.ts drives the real published feed in a browser and fails against the old code with "the 25N bus 15_0_D_4_2510 is missing from the board at 00:30"; with the fix that bus reads "in 40 min" at 00:30, and a control asserts it is gone once its service day is over.
ciotlosm
force-pushed
the
fix/service-day-night-routes
branch
from
October 24, 2026 18:41
a2f4a0c to
98a1adc
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Between midnight and the end of the night service, the buses that were actually running vanished from the station board - and the ETA arithmetic came out ~24 h out.
The cause
A GTFS service day is not a calendar day. It starts at 00:00 and can run past midnight: a trip published at
"25:10"departs at 01:10 the next morning and belongs to the previous calendar date's service day. Feeds that run night services publish exactly that - the Cluj feed's25N/5N/54Nlines use24:00-25:33.The app resolved "what is running now" against the calendar date, so during the post-midnight window the service day in progress was the wrong one and the still-running night buses were dropped from the board at exactly the moment they started running. The same class of error made every ETA computed against a schedule time from the other timeline read ~24 h out.
Measured on the real published feed, at Monday 00:30 the bus that departs at 01:10 was simply absent; with the fix it reads "in 40 min".
The fix
New module
src/lib/domain/pipeline/serviceDay.tsis the single place that answers "which service days are in progress, and where do their trip times land".Between local midnight and the rollover hour (04:00 - the convention already assumed in
config.ts) two service days are in progress at once, so the station board, the reconciler's active-trip set, the map view, the favourites "active routes" set and the schedule grid all query both of them and shift the previous day's times by -1440 onto the shared timeline.nowitself stays where it was - minutes since local midnight - so every other consumer is unaffected.The live side needed one more thing: a GTFS-RT observation carries the trip's service date, and for a night trip that is the previous date, so the orphan ETA seed now uses it instead of assuming the observation belongs to the current service day.
Also fixes the station board wiping the ETA the reconciler had already seeded onto an orphan row.
Verification
tests/night-routes.spec.tsdrives the real published feed in a browser with an explicit clock, and fails against the old code with:A control asserts the same bus is gone once its service day is over. Plus a unit test for the service-day model itself.
pnpm check-> 0 errors,pnpm test-> 396 passed,pnpm build-> OK (verified on this branch in isolation).