Blog
Dates, dashboards and the work that has not processed
A dashboard can look current while timezone assumptions or a hidden row limit say otherwise. I'm putting unprocessed records, date rules and result limits on the screen, because people running operations need to see incomplete work before a customer complaint tells them about it.

"Today", "complete" and "all records" each depend on a rule somewhere. If the dashboard hides those rules, the query can be perfectly consistent and still give the wrong answer to the person looking at it. The ones I care about are the timezone, how fresh the data is, processing state, the filters and any limit on how many rows get considered.
Timezones first. A timestamp is an instant, but a calendar day belongs to a timezone, so grouping by date without picking one moves work across the boundary (you'll see it most around midnight). Store event timestamps as UTC, keeping the source timezone if it means something to the business, convert to the reporting timezone and only then work out the local date. Don't take a UTC date and relabel it as local. Decide whether the dashboard follows the organisation, the site, the user or the event, put that in the metric definition, and show the active timezone near the date filters, with a label like 20 Dec, 9:00 am AEDT when the exact instant matters.
Most records have more than one relevant time, too. An order gets created, received by an integration, processed by a worker and displayed later, and filtering on the wrong one can make a backlog disappear from one day and turn up in another. I'd name timestamps for the events they represent: created_at, received_at, processing_started_at, processed_at and failed_at. A generic date column invites every part of the app to read it differently, and if the screen says "received today" it shouldn't be filtering on the day a delayed job finally finished.
A completed-work chart can't show you items that never reached completed. Put backlog and failure counts next to the number they qualify, and split them up, because waiting normally, currently processing, delayed past the expected threshold, rejected for correction and stuck after a worker interruption each mean something different for staff. Ten items waiting for the next scheduled run aren't the same as ten that have sat there for two days, so show the oldest waiting time and link the counts to the actual records.
Then there's the row limit. Dashboards often cap rows, date ranges, API pages or chart points for performance, and if the screen doesn't say so, people read the result as complete. Fetching the first thousand rows and counting them doesn't give you a count of all matching records. Filter and aggregate in the data store before limiting, follow pagination until the scope is done (or label the result partial), and when a limit is deliberate, show it. "Displaying 500 of 2,346 matching records" gives the user something to decide on. Test just below, at and above every configured limit, since ordinary test data is rarely big enough to trip it.
When a dashboard says "today", "complete" or "all records", the person reading it should be able to see the rule behind each word: the timezone, which timestamp is being filtered, what hasn't processed yet and whether a limit cut the result short. Without that, the screen looks current and the unprocessed work only turns up when a customer complains about it. For the release check, I'd ask someone who uses the screen to explain one number: which records it includes, as at what time, in which timezone and what's left outside it. Anything they had to ask a developer about, or dig through source code to find, goes into the metric definition or the interface.
On X
Got a take on this?
Share it on X. I read the replies.