Why do servers run on UTC instead of local time?
A server in New York logging events in local time records an error at 02:15 on the second Sunday of March. The next day, that timestamp does not exist. Clocks jumped from 02:00 to 03:00. A week later, you try to find the error by scanning logs in chronological order. You cannot. The log has a gap.
UTC does not observe daylight saving time. Its offset is always UTC+0, every day of the year. When every machine on a network agrees on the same time reference, you can sort logs, merge database rows, and correlate events across continents without translation errors. On 15 January 2026, New York sits 5 hours behind UTC. On 15 July 2026, New York sits 4 hours behind UTC. Same city, same hardware, different offset. UTC removes that variable.
Server logs: how UTC avoids DST chaos
Servers should log in UTC. Period.
The "fall back" clock change in November repeats the hour from 01:00 to 02:00. If your application logs in local time, events from that hour carry duplicate labels. Which event happened first? You cannot tell without secondary data. The "spring forward" change in March skips an hour entirely. Events that should exist have no label at all. Log analysis tools break. Alerting rules that depend on time ranges misfire.
Logs in UTC produce a monotonic sequence. Each entry carries a unique, increasing marker. Debugging a production incident across a fleet of servers becomes a simple sort operation. Elasticsearch, Splunk, Datadog: all assume log entries are in UTC or can be normalised to it.
Database best practice: store in UTC, display local
Store time values in UTC. Convert to local time only for display. This is not optional. It is the difference between a correct query and silent data corruption.
A user in Paris books a meeting for 14:00 local time on 25 October 2026. Paris switches from CEST (UTC+2) to CET (UTC+1) on the last Sunday of October. If you store the local time without offset, the database holds "14:00". But at what UTC did the meeting occur? Before the clock change, 14:00 CEST is 12:00 UTC. After the clock change, 14:00 CET is 13:00 UTC. Same local string, different actual moment.
Store the UTC value (2026-10-25T12:00:00Z). When the user views their calendar, convert to Paris local time. The database never lies.
PostgreSQL (TIMESTAMPTZ), MySQL (time zone conversion at query time), MongoDB (ISODate), Amazon RDS, Google Cloud SQL: all expect or work best with UTC in the storage layer.
Cloud services: AWS, Azure, and GCP all use UTC
Amazon Web Services, Microsoft Azure, and Google Cloud Platform run their internal infrastructure on UTC.
Lambda execution logs carry UTC markers. Cosmos DB stores time values as milliseconds since Unix epoch, which is UTC-based. Google Cloud Console shows all event times in UTC by default. Provision a cloud resource and the billing cycle, the metrics dashboard, the API response times all refer to UTC. If your application logic uses local time to compute a cloud billing period, you risk cut-off errors. Cloud vendors document every time-based feature in UTC. Match their convention.
API design: always return UTC
If your API returns a time value in local time, every client must know your time zone to parse it. They cannot. They will guess, and they will guess wrong.
Return all time values in ISO 8601 format with a trailing "Z" (Zulu, meaning UTC). Example: 2026-01-15T14:30:00Z. The "Z" is unambiguous. No time zone offset parsing. No DST guesswork.
For REST APIs, the HTTP header Date is already required to be in RFC 7231 format, which uses UTC. Follow the same pattern in your response bodies. For GraphQL, use the DateTime scalar that serialises to ISO 8601 with Z. For gRPC, use the google.protobuf.Timestamp type, which stores seconds since Unix epoch: again, UTC-based.
The DST overlap: why local time scheduling fails
The most dangerous DST moment is the overlap. At 02:00 on the first Sunday of November 2026 in New York, clocks fall back to 01:00. The hour from 01:00 to 02:00 happens twice.
If your application schedules a job at "01:30 local time" during this night, which 01:30? The first occurrence (04:30 UTC) or the second (05:30 UTC)? The scheduler cannot tell. Jobs may fire twice, or not at all.
This is not a hypothetical edge case. Every year, production systems fail during DST transitions because they rely on local time scheduling. The fix: schedule everything in UTC. Convert to local time for the user's calendar display, but keep the execution trigger in UTC. Then the "fall back" night is just a normal UTC day.
Setting your server to UTC
Linux: sudo timedatectl set-timezone Etc/UTC or sudo ln -sf /usr/share/zoneinfo/Etc/UTC /etc/localtime. Verify with timedatectl.
Windows: Set system time zone to UTC (Coordinated Universal Time). Windows will still apply DST to some local time display, but the system clock itself ticks in UTC.
macOS: sudo systemsetup -settimezone UTC.
Container images: Set the time zone at build time. For Docker, add ENV TZ=Etc/UTC to your Dockerfile. Kubernetes nodes should already be set to UTC by default in most cloud distributions.
Do not rely on the host machine's time zone. Every container should explicitly set its time zone to UTC. Otherwise, a developer building an image in Paris gets a container with Europe/Paris time, which then fails in production on AWS, where the host runs UTC.
Docker and Kubernetes: time zone in containers
Docker containers inherit the host's system time unless told otherwise. Kubernetes pods may run on nodes in different physical data centres. If one pod logs in UTC and another logs in America/New_York, correlating their timelines is manual work.
Set TZ=Etc/UTC in every container's environment. Kubernetes has no global time zone setting per cluster. You must configure it per deployment. Helm charts should include an environment variable block for time zone.
Monitoring and alerting: UTC for incident response
When a page goes off-call at 02:00 local time, and the on-call engineer is in a different time zone, the handover window depends on who knows whose offset. This is a people problem, but it starts with data.
PagerDuty, Opsgenie, Grafana: all use UTC internally. The incident timeline shows UTC. Escalation rules evaluate in UTC. If your monitoring dashboard is set to local time, the 2:00 AM alert you see as "2:00" might actually be 7:00 UTC, meaning the issue started during a different shift.
Set your monitoring dashboards to UTC. Learn to read UTC natively. It takes a week.
How NTP syncs computers to UTC
A computer's clock drifts. Without correction, it loses or gains seconds every day. Network Time Protocol (NTP) fixes this by synchronising to UTC.
NTP uses a hierarchy of levels. Level 0 is the reference clock: an atomic clock or a GPS receiver that directly derives time from satellite signals. Level 1 servers connect directly to Level 0 sources. Level 2 servers sync from Level 1, and Level 3 clients sync from Level 2.
Over the public internet, NTP typically achieves accuracy within milliseconds. For most IT purposes, that is sufficient. For high-frequency trading databases that need microsecond precision, organisations run their own Level 1 server on-premises.
Linux uses ntpd or chronyd. Windows uses ntp.exe. Both query Level 2 or Level 3 pools, like pool.ntp.org.
How do Unix time values handle leap seconds?
Unix time counts seconds since 1970-01-01T00:00:00Z. But it does not count leap seconds. When a leap second occurs (the last one was on 31 December 2016), the Unix time value stutters. The value for 23:59:59 UTC and the value for the leap second 23:59:60 are identical. The system sees the same number twice.
This breaks any software that assumes time values are strictly increasing. Google and Amazon handle this by "smearing" the leap second across the day: slowing the clock slightly over several hours so the extra second is absorbed without a stutter. POSIX time, the specification Unix time values are based on, simply ignores leap seconds.
If your database stores Unix time values, it already excludes leap seconds. This is fine for almost all applications. But if you need to correlate with astronomical observations or GPS time (which runs ahead of UTC by 18 seconds as of 2026), you must account for the difference.
Will the Year 2038 problem break my systems?
Unix time values on 32-bit systems are stored as a signed 32-bit integer. The maximum value corresponds to 19 January 2038 at 03:14:07 UTC. One second later, the integer overflows to a negative number representing 13 December 1901.
Any 32-bit system that tracks time as a signed 32-bit integer will break on that date. Most modern servers, cloud instances, and mobile devices are 64-bit, which can handle dates billions of years into the future. But embedded systems, some industrial controllers, and older network equipment may still run 32-bit software.
The fix: migrate to 64-bit time representations now. Python, Java, Go already use 64-bit for time. C and C++ code on 32-bit targets needs explicit auditing.