Most operators inherit a time clock and never look inside it — fine until a week's total looks wrong and you need to know whether the software is lying, the tablet is lying, or somebody forgot to clock out. Everything here is the mechanism we built for a multi-store franchise replacing a scheduling-and-clock product, including the bugs we found doing it.
Pairing: a day is four punches, not one entry
The right mental model is not "hours worked today". It's a list of stamped events, each carrying a kind. For a normal shift with one break, four of them:
in— 09:02break_start— 12:30break_end— 13:02out— 17:28
Hours worked is then derived, not entered: pair each in with the next out, sum the spans, and subtract every paired break falling inside a span. Nothing is stored as "8.1 hours" — the total is always computed from the events, so it audits back to what physically happened at the tablet. One number has no provenance; four timestamps mean a questioned total has an answer.
Subtracting breaks, and the overtime arithmetic
Break handling has exactly two honest models, and you must pick one deliberately:
- Punched breaks. The person clocks out and back in for lunch. Actual minutes, subtracted exactly. Accurate; requires four taps a day instead of two.
- Automatic deduction by rule. A shift over some length has a fixed unpaid break deducted. Two taps a day; wrong whenever reality differs from the rule, and in some jurisdictions auto-deducting a break the person did not take is a legal problem, not just an accuracy one.
Our clock uses punched breaks. If you choose auto-deduction, make the deduction visible on the timesheet as its own line rather than baked into the total — an invisible deduction is indistinguishable from a bug.
Overtime then falls out of the weekly sum. Work it with your own numbers rather than trusting a dashboard:
| Day | Elapsed | Break | Paid |
|---|---|---|---|
| Mon | 8h 26m | 32m | 7.90 |
| Tue | 9h 10m | 30m | 8.67 |
| Wed | 8h 05m | 0m | 8.08 |
| Thu | 9h 40m | 30m | 9.17 |
| Fri | 8h 30m | 30m | 8.00 |
| Week | 41.82 |
Against a 40-hour weekly threshold that's 40.00 straight plus 1.82 overtime — produced entirely by two long days and one skipped break. At $18/hour those 1.82 hours cost $49.14 at time-and-a-half, $16.38 of it pure premium you wouldn't have paid had the break been taken. Trivial once; not trivial across 30 people and 52 weeks. Overtime rules vary by state and employment type, so confirm your own threshold — the point of the table is that OT is a consequence of punch quality, not something the software decides separately.
Downstream, those per-day paid figures and the overtime split are what feed the weekly workbook the bookkeeper actually files — hours and OT per store, leave columns left blank for hand-fill. It's a workbook for a human to check. It is not a payroll processor: it doesn't file taxes and it doesn't move money.
What a missing out-punch does to a week
Somebody clocks in Tuesday at 09:02 and goes home without clocking out. What happens next depends entirely on how the system treats an unpaired in, and there are three common behaviours — two of which are wrong:
- It keeps counting. By Friday the shift is 70+ hours long and the week's total is fiction. Worse, every hour of it lands above the overtime threshold.
- It silently discards the day. The week is short by a full shift and the person is underpaid unless they notice.
- It flags the day as an exception and pays nothing until a human resolves it. Correct.
An exception should name the specific problem — "no out punch, Tuesday" — and be resolvable in one place with the day's existing punches visible. Our fix drawer shows four slots in shift order, prints the day's existing punches with their source, and draws a red "— —" where a kind is missing, so the gap is obvious before you type anything.
The discipline that goes with it: clear exceptions daily, not on payroll morning. A gap resolved next day is a manager asking "what time did you leave?" and getting a real answer. The same gap six days later is a guess that becomes a payroll record.
Want to see your own exceptions? If your current clock's week totals don't reconcile, book a demo — bring last week's timesheet and we'll walk the punches with you.
Why an open shift today is not an exception
At 2pm on Wednesday, every person currently working has an in with no out. That is not a missing punch — it's the definition of being at work. If the system flags them, the exceptions list on any weekday afternoon contains your entire working staff, the real problems are buried, and within a week nobody opens the list at all.
So the rule is temporal, not structural:
- Open
in, today: not an exception. Show it as a status — "on the clock now" — in the day's view, no alarm. - Open
in, any prior day: a real exception. Flag it, don't pay it until resolved.
We shipped exactly this: a person clocked in today gets an "in now" marker on their row, and only prior-day opens raise the missing-out-punch flag. The principle generalises to any operational alert — one that fires on the normal case trains people to ignore it, and then it doesn't fire for the abnormal case either, because nobody's looking.
Store every punch in a real timezone, never bare UTC
Storing timestamps in UTC is normal and correct for machine-to-machine data. But a punch is not machine data — it's a claim about local wall-clock time at a store. "Clocked in at 9:02" means 9:02 on that store's wall. Those are different statements, and the difference is where the bugs live:
- Manager corrections. A manager types "09:05" for yesterday. If that string is stored as though it were already UTC, the punch lands hours away from where it belongs. We had exactly this defect: manager-entered times were stored verbatim, which shifted them by 4–5 hours depending on the date. A shift entered as 9am–5pm became a shift that started at 5am.
- Daylight saving. The offset between local and UTC is not a constant. Any conversion done with a fixed number is wrong for half the year — and it's wrong in a way that only shows up months after you shipped it.
- Day boundaries. Group punches by their UTC date and anything after 7pm Eastern lands on the next calendar day. We hit this on a daily-count feature: an 8pm closing count appeared on tomorrow's line. On a timesheet that's a Tuesday evening punch reported as Wednesday — both days wrong, and any daily overtime rule with them.
The fix is a pair of explicit conversions used everywhere — local-to-UTC when you take a time from a human, UTC-to-local when you display or group one — both daylight-saving aware, never a hardcoded offset. For a day view, compute the window in local time (00:00 to 23:59 local, converted) rather than slicing a UTC string. Ask any vendor how they handle this: "we store everything in UTC" is half an answer, and the other half is which timezone they convert back into.
Kiosk punches immutable, manager fixes audited and reversible
A time clock is a payroll record, so it has to be defensible to the person being paid and to anyone reviewing it later. Two rules that sound restrictive and are what make it trustworthy:
- A punch made at the kiosk can never be edited or deleted. Not by a manager, not by an owner. It's what the tablet recorded. If a manager could quietly change it, the record proves nothing and every dispute becomes one person's word against another's.
- A manager correction is a separate, labelled, reversible entry. It carries who made it and when, shows on the timesheet tagged as a fix rather than as a kiosk punch, and can be deleted — because a correction can itself be wrong.
In our clock, the delete endpoint refuses any punch that didn't come from a manager. The payoff is the conversation: when someone says "I worked until 5:30," you can show them the four rows and which one a manager added on Monday. Either the record supports them or it doesn't, and nobody argues about what the software might have done. Scope matters too — a manager should only be able to fix punches at stores they're responsible for, and an unassigned manager should see nothing rather than everything. Fail closed.
PIN identity on a shared tablet beats a dropdown of names
On a shared counter tablet, the temptation is a list of faces or names: tap yours, you're clocked in. Do not do this. A dropdown of names is an authorisation-free clock — anyone can tap anyone. Buddy punching stops being a policy violation and becomes a two-tap gesture, and a manager reviewing the week has no way to distinguish.
A 4-digit PIN fixes it cheaply:
- It's a secret, so the punch means something. Not strong security — four digits never is — but clocking in for someone else now requires them to have told you their PIN, a deliberate act you can have a policy about.
- It doesn't leak the roster. A dropdown shows every employee's name to every customer at the counter. A keypad shows nothing.
- It's fast, and stays fast. Four taps, no scrolling past 30 names — and it's still four taps when the roster doubles.
- It's the front door for everything else. Once a PIN starts a kiosk session, the same gesture authorises the other things a counter tablet does — witnessing a transaction, starting a quote — with a named person attached to each.
Details that matter: store PINs hashed, never plain text; let employees set their own rather than having a manager assign one (a manager who knows your PIN can punch as you); reject weak and duplicate PINs at the point of choosing, because two people sharing 1234 makes the scheme meaningless. Ours does all three, with an admin regenerate as the fallback.
Honest closing note: one store, five people, everyone hourly, no breaks — a paper sheet on a clipboard genuinely works and you shouldn't buy software for it. The mechanics above start paying when punches split across locations, when overtime sits close enough to the threshold that break accuracy changes the number, or when a bookkeeper retypes totals every Monday. That's what our time clock and the wider workforce ops product were built for — and how we line up against When I Work has the feature-by-feature version.