Flow
What a date range can mean
A description of the two options, not a measurement.
1Whole local days
The caller names days on its own clock and the server turns the edges into exact times, so range and bars agree.
2A stretch of time
The caller sends two exact times, and the first and last bars are partial and labeled that way.
3Where this change landed
Bars use the viewer's clock while the edges stay at UTC midnight, with no label saying so.
Days were being counted on the wrong clock in the daily charts. They asked the database for the date of each stored time without saying which time zone to use, so the database used its own, which is almost always UTC on a server. For anyone west of London, that day ends in the afternoon or evening. Late work showed up on tomorrow's bar. The totals were right and the labels were wrong.
Copying the hourly chart
One hourly chart already sent the browser's time zone with its request. This change shares that lookup, sends the zone with the daily requests too, and converts each time into that zone before taking the date. Do it in that order: convert, then take the date, then group. If you group first, the split at UTC midnight has already happened.
Bound in one place, pasted in another
The daily queries live in two places, and they don't treat the zone the same way.
The shared query helpers require the zone and send it to the database as a separate value, not as part of the SQL text. That's the safe way. A missing zone stops the build, and a strange one is just a value.
The summary route reads the zone from the URL, uses UTC if it's missing, and pastes it into the SQL text of three queries. A browser sends a clean zone name. Anything else can send a quote mark and extra SQL. I haven't tested how far that would get, but a client string inside SQL text is a problem whatever the answer is.
The same commit added a small check for whether a zone name is real. Nothing calls it. Even if something did, I'd still send the zone as a separate value, because the browser's list of zones and the database's list might not match.
What a missing zone does
The helpers refuse to run without a zone. The route falls back to UTC, which brings back the exact bug this change was fixing, without any sign that it happened.
Partial bars at both ends
The labels moved to the viewer's clock, but the start and end of the date range are still at UTC midnight. For someone behind UTC, the first bar is missing part of its day and the last bar takes some hours from the next one. There are no tests in this commit for any of it. A range can honestly mean one of two things: whole local days, with the edges converted on the server, or a stretch of time with partial bars at each end that the chart labels as partial. This change behaves like the second without saying so.