Software Development

Time Zones and Dates: The Bugs That Keep Coming Back

Updated October 17, 2017By the CalliArc team

Key takeaway

Store instants in UTC, but store future appointments as a local time plus a time zone identifier — because if a government changes the daylight saving rules, a meeting at 9am must still be at 9am. Getting that distinction right prevents most recurring date bugs.

Date bugs have a characteristic rhythm: everything works until the clocks change, or until a customer in another country complains, or until the last day of the month. They're avoidable, but only with rules applied consistently.

The core distinction

  • An instant — something that happened — is a point on the timeline. Store it in UTC, convert for display.
  • A future local commitment — an appointment, a recurring meeting, a delivery window — is a wall-clock time in a place. Store the local time and the IANA time zone identifier, and compute the instant when you need it.
  • Storing a future appointment as UTC is the classic bug: when the daylight saving rules for that region change, every future booking shifts by an hour.
  • A date without a time — a birthday, an invoice date — is a calendar date, not midnight in some time zone. Store it as a date.

Daylight saving will break your assumptions

  • Some local times don't exist (the hour skipped in spring) and some occur twice (the hour repeated in autumn). Your booking system must handle both.
  • A day is not always 24 hours, and adding 86,400 seconds is not the same as adding one day.
  • Time zone rules change by legislation, sometimes with weeks of notice. Keep your time zone database updated as part of routine maintenance.
  • Never store a fixed UTC offset in place of a zone identifier; "+05:30" loses the rule that produced it.

Recurring events

"Every Tuesday at 9am" is a rule, not a list of timestamps. Store the rule with its time zone and generate occurrences on demand, keeping explicit exceptions for instances that were moved or cancelled. Expanding a recurrence into thousands of stored rows means every rule change becomes a data migration.

Business time is its own problem

  • Business days, working hours, and holidays are per country, per region, and sometimes per customer. Make the calendar data, not code.
  • Service level agreements measured in business hours need that calendar to be correct historically, not just today.
  • Month-end and year-end arithmetic has edge cases — adding one month to 31 January has no obvious answer, so define yours.
  • Test with a fixed, injectable clock so date-dependent logic is testable at all, including across a daylight saving boundary.
Share LinkedIn X

Ready to build it right?

Get a transparent, milestone-based estimate for your project in a free consultation.

Book a free strategy call