An 8-article series covering everything you need to know about handling dates, times, and timezones correctly in software.
Why This Series Exists
This series didn't start as an attempt to write about time.
It started with a concrete problem: designing a DateTimePicker.
At first, the questions seemed simple:
- Do I need timezone support?
- Should the picker return a UTC timestamp or a local value?
- What does "10:00" actually mean in a system used across regions?
But each answer led to more questions.
What looks like "just a date and time" quickly becomes questions about:
- What does the user actually mean?
- How do calendars and timezones interact?
- What happens with DST, recurring rules, and timezone changes?
- What does it even mean to store a time correctly?
Trying to answer those questions forced me to step back and build a clearer mental model of time in software — from first principles to concrete implementations.
This series is the result of that process.
New articles will be published over time and linked here as the series progresses.
Article 1: Why a Date Is Not a Point in Time
The fundamental misconception: Explains why "Christmas" or "June 5th" are not moments in time, but calendar-day windows that slide across the planet. Breaks down the difference between calendar concepts and physical time.
Key insight: A date is not a moment — it needs both a time and a timezone to become one.
Article 2: The 7 Types of Time Every Developer Must Know
Shared vocabulary: Defines Instant, Local Date, Local Time, Local DateTime, Zoned DateTime, Offset DateTime, and Recurring Rules. Includes a bonus section on Duration vs Period (time amounts vs time points).
Key insight: Most datetime bugs come from mixing up different types of time.
Article 3: Deadlines Are Hard
Why vague deadlines fail: Shows why "Submit by June 5th" is fundamentally broken. Explores server time vs user time vs organization time, and why guessing midnight is dangerous.
Key insight: If users can't objectively know whether they've met a deadline, the deadline is broken — not the user.
Article 4: Instant vs Local – When UTC Helps and When It Hurts
The core model: Explains when to use UTC (logs, audits) and when it destroys meaning (meetings, appointments). Introduces the correct pattern: store local + timeZoneId as truth, derive instantUtc for queries. Covers DST changes and why IANA timezones are about rules, not geography.
Key insight: Store intent, not math — future instants recalculate when timezone rules change.
Article 5: Global Events, Local Events, and Recurring Rules
Event semantics: Distinguishes "same moment worldwide" (global events using Instant) from "same clock reading" (local events using Local DateTime + timezone). Covers recurring rules, DST edge cases (gaps and overlaps), and why cron jobs differ from calendar events.
Key insight: "All stores open at 10:00" means different instants around the world.
Article 6: .NET in Practice – Modelling Time with NodaTime
Backend implementation: Shows how to use NodaTime types (Instant, LocalDate, LocalDateTime, ZonedDateTime) in .NET. Covers BCL alternatives (DateOnly, TimeOnly), DST handling, real-world examples, EF Core mapping, and testing with IClock.
Key insight: Inject IClock instead of calling SystemClock.Instance directly — your tests will thank you.
Article 7: PostgreSQL – Storing Time Without Lying to Yourself
Database storage: Explains timestamp vs timestamptz, why timestamptz doesn't actually store timezone, the correct pattern (local_start + time_zone_id), DST-safe queries, and indexing strategies.
Key insight: timestamptz stores UTC, not the timezone — if you need to preserve user intent, store the local time and timezone separately.
Article 8: Frontend – Temporal, APIs, and DateTimePickers That Don't Lie
Frontend implementation: Covers the Temporal API (Temporal.PlainDate, Temporal.PlainDateTime, Temporal.ZonedDateTime), API contract design (structured objects vs ISO strings), and DateTimePicker principles. Includes timezone detection in browsers and when to show (or hide) timezone UI.
Key insight: The picker's display should match what gets stored — don't lie to users about what's being saved.
Summary
| # | Title | Layer |
|---|---|---|
| 1 | Why a Date Is Not a Point in Time | Concepts |
| 2 | The 7 Types of Time Every Developer Must Know | Vocabulary |
| 3 | Deadlines Are Hard | Requirements |
| 4 | Instant vs Local – When UTC Helps and When It Hurts | Core Model |
| 5 | Global Events, Local Events, and Recurring Rules | Event Semantics |
| 6 | .NET in Practice – Modelling Time with NodaTime | Backend (.NET) |
| 7 | PostgreSQL – Storing Time Without Lying to Yourself | Database (PostgreSQL) |
| 8 | Frontend – Temporal, APIs, and DateTimePickers | Frontend (JavaScript) |
8 articles total — each stands alone, but together they form a complete mental model for handling time correctly in software.
Top comments (0)