Functional patterns
Reusable approaches for handling time correctly in practice.
Parsing user input
Human input is ambiguous and locale-dependent — never trust a lenient parser with it.
Your own client ↔ server
You control both ends — agree one explicit wire contract and serialize symmetrically.
3rd-party data
Trust but verify — validate external timestamps against an expected format and fail loudly.
The lowest common denominator
A value that crosses N systems lives in the intersection of their type systems — design for the weakest hop, and make the loss explicit.
Store vs display
Store instants in UTC; convert to the user’s local zone only at display time.
Formatting for display
Delegate to a locale-aware formatter, always with an explicit zone; never hand-assemble date strings.
Recurring events
A recurrence names civil times, not instants — store the rule and the zone, and materialize occurrences as late as possible.
Your schema is a contract
Your database schema is an interface other teams read — clear types and unambiguous names keep ETL jobs and analysts from guessing wrong.
Naming time fields
Encode the meaning in the name —
_at for instants, _on for dates, _local/_utc when the type can’t say it, units for durations.
The rules
Every “always” and “never” in this guide, distilled into one deep-linkable list — share a rule by its link.
Pitfalls & anti-patterns
A citable index of the warnings scattered across this guide.