Understanding How We Keep Track of Time
Time is a measurement system, not a physical thing. That distinction matters more than most people realize when they run into problems with scheduling software, international coordination, or daylight saving transitions. I spent years building systems that had to handle time across multiple zones, and the issues are almost never what beginners expect. When someone asks "What Time Is It" and expects a single answer, they're missing the fundamental issue: there is no single answer. Every location has its own local time, and the offsets change because governments keep rewriting the rules. I remember a project where a client in Paraguay switched their DST rules mid-year, and every scheduled report ran four hours off for three weeks. The fix wasn't complicated, but the debugging took two full days because the source of the offset change was buried in a government decree nobody at the company had read. The core concept here is UTC. Coordinated Universal Time is the reference point everything else branches from. It doesn't change for daylight saving, it doesn't jump around, and it's what you should be storing in your database. Everything else is a display layer on top of that. A common mistake I see is storing timestamps as local time strings instead of UTC offsets. That creates a nightmare when someone travels or when your users span multiple zones.
How Time Zones Actually Work
Time zones are defined by the IANA Time Zone Database, commonly called tzdata. This database gets updated regularly as countries change their rules. When your server or application queries "What time is it in America/New_York?" it pulls from this database to apply the correct UTC offset for that specific moment in time. The problem is that most people treat time zone handling as a one-time setup rather than an ongoing maintenance task. The library you use matters. In Python, pytz is outdated and contains historical baggage. zoneinfo, built into Python 3.9+, reads directly from the system's tzdata. In JavaScript, moment-timezone used to be the standard, but dayjs with its timezone plugin or even the native Intl.DateTimeFormat are better choices now. Each has different behavior around ambiguous times during fall transitions, which is where most bugs hide.
Ambiguous Times and the Gap Problem
Here's something most tutorials skip. When DST ends, one hour repeats. If your system schedules something for 1:30 AM and that hour happens twice, which occurrence do you mean? Conversely, when DST starts, an hour disappears. 2:00 AM jumps to 3:00 AM. Any schedule set for that missing window simply never fires. I've seen production incidents where recurring meetings vanished for a week because nobody accounted for the gap. The workaround is straightforward but unintuitive. Never schedule events during transition hours. Push all recurring events to either before 1:00 AM or after 3:00 AM UTC, which avoids the problem entirely since UTC doesn't observe DST. Alternatively, store the UTC timestamp directly and let the display layer convert it for the user at render time. The conversion will show the correct local time regardless of which side of the transition the event falls on.
Get the Full Details

What Time Is It What Time in Practice
If you're building something that needs to show time to users, the pattern is simple. Store everything in UTC. Convert to the user's local timezone only at the point of display, using their browser or app settings to determine the target zone. Don't ask users to pick their timezone manually if you can avoid it. Most modern browsers expose the local offset through the Intl API, and that data is reliable enough for display purposes. For cross-border applications, you need to handle the case where a user's timezone changes mid-session. I worked on a system where a business traveler flew from London to Tokyo during an active meeting, and the calendar widget showed the next meeting as happening in the past from their new location while it was still minutes away from their original seat. The fix was recalculating all displayed times whenever the user's detected timezone changed, which is a detail almost no one builds in until it becomes a support ticket.
Common Pitfalls That Waste Hours
Comparing timestamps without normalizing to the same timezone is the simplest way to break scheduling logic. A string comparison between "2024-03-10 01:00" and "2024-03-10 01:00" looks identical, but if one is EST and the other is EDT, they're thirty minutes apart. Always normalize to UTC before any comparison operation, and make it explicit in your code so future developers don't revert to lazy string matching. Server configuration is another silent breaker. If your application server runs in one timezone but your database runs in another, and you're not careful about which one stores and returns timestamps, you'll get results that look correct most of the time and are wrong during edge cases. Check your server's TZ environment variable and your database's time_zone setting. They should align, or you should explicitly convert at the application boundary. There's no perfect solution for time. Governments change rules without warning, and some regions have offsets that aren't whole hours. But if you store UTC, convert at the display layer, and never schedule through transition windows, your system will handle 99% of real-world cases correctly without constant babysitting.