Most systems being designed are heavily dependent on accurate time. Time Zones (and worse, daylight savings) do not make time handling very easy. For applications to handle this correctly, they have to rely heavily on the configuration of the underlying time infrastructure.
What is UTC?
UTC stands for Coordinated Universal Time and according to Wikipedia:
UTC, is the primary time standard by which the world regulates clocks and time. It does not observe daylight savings.
Time zones around the world are expressed using positive or negative offsets from UTC.
Differentiate between Physical (Model) Time and Civil (Presentation) Time
Theoretically, there are two types of time and we need to distinguish between them.
- Physical Time is a point in time that physics deals with. We can usually persist this value in UTC. This is what our infrastructure and our systems should work in. This remains unique for back-end and mid-tiers so the users never see this.
- On the other hand, there is Civil Time. This kind of time follows civil norms such as Date and Time Format (dd/MM/YYYY or MM.dd.YYYY), Time Zones, Calendar Type (ex. Gregorian, Islamic, Hebrew). This kind of time is what we present to the users.
Time Zone is not an Offset
Before we start, I would like to emphasize that a Time Zone can not be exclusively represented by an offset from UTC. Many time zones observe daylight savings time; so a certain offset for a time zone can change depending on the time of the year.
Time Zone Databases
There are 2 major time zone databases commonly used:
- The Microsoft Time Zone Database is built in the Windows Operating System and is easy to consume from Win32 APIs of .NET Framework. Updates to this database are deployed automatically through Windows Update[1]. This database is not good with historical time zone changes and is maintained by Microsoft instead of a standards body, which some people consider as disadvantages.
- The IANA Time Zone Database[2] is widely implemented on Linux, Mac, Java and other platforms. There are also libraries for Javascript and .NET. Unlike Microsoft's Database, this database contains historical data for time zone changes and is Community Maintained (and recently backed by IANA). It is also updated several times a year.
The Infrastructure Side
Everything in your infrastructure should persist time in UTC. This means, your routers, firewalls, switches, web servers, database servers, etc... If you run an Active Directory infrastructure, you can roll out a GPO on all your servers to set their Time Zone to UTC. This is important because UTC does not observe daylight savings.
It is also very important (especially in geographically distributed systems) to synchronize to a common time-source. You should have one single source of truth in your infrastructure. Only one of your servers should synchronize time from an external time source; the rest should synchronize with that internal server[3]. Everything you own should run an NTP client and synchronize time with your Time Servers. This is important because you want to keep consistency between events that happen on different (and perhaps even geographically distributed) servers.
Time is also very important in an Active Directory environment. Windows AD needs timestamps for resolving AD replication conflicts and for Kerberos authentication[4]. When a Windows server receives a Kerberos authentication request, it compares the timestamp in the request to its local time. If the difference between the local time and the timestamp is too big, the authentication request is rejected and Kerberos authentication fails. The default setting is five minutes[5].
Keep your Time Zone data updated; these change (a lot!). Usually these are updated with your OS (another reason to keep your OSes up to date)
Be aware of clock drift. When your clock is out of sync with a time source, the time on your clock does not immediately change to reflect the server's time source. You also need to be aware that NTP does not move the time backwards; this may badly impact some applications you may be running (example Databases). Rather NTP will drift the clock by slowing down (or increasing the speed of) the system clock. This is called slew correction.
The Application Side
This might sound obvious, but you should never, ever, ever, code your own time libraries. Check out Computerphile's video at the bottom.
Like your infrastructure, the application should persist time in UTC. Most applications automatically inherit the time settings from the servers they are running on. As a developer, you should not expect the time zone of the server to be set to UTC. Force your application to save time in UTC; the infrastructure might be incorrectly configured.
If, for some reason, you choose to persist a time using local time value, include the offset (at the time of saving) from UTC. Using the offset, the time can be later interpreted precisely.
When you need to save time for future events, UTC is not the right answer! In short, from the time you persist the time of the event, to the time the event will actually happen, Daylight Savings rules might change[6], the offset of the time zone might change, or the time zone of the location might change, or any combination of these changes might occur as Jorge Alberto Gómez Prada duly noted in the comments section. Instead of saving the time in UTC along with the time zone, developers can save what the user expects us to save: the wall time. i.e. what the clock on the wall will say.
When saving Time Zone offsets, remember that they are not always an integer number of hours. For example: Eucla is (UTC+08:45), Kathmandu is (UTC+05:45) and Caracas is (UTC-04:30)
Remember, that Time Zones, Offsets and Daylight Savings rules are not fixed and change (a lot more than you'd expect!).
When ingesting time from a third-party provider make sure that there is no ambiguity in the data being ingested. Is there a time zone or offset explicitly defined? Do they follow DST?
In .NET
If you're serious about time in your .NET application, you should use a library like Noda Time. .NET provides far too few types to represent date and time values in a way which encourages the developer to really consider what kind of data they're dealing with... which in turn makes it hard to treat the data consistently[7].
If you are not using Noda Time, consider using DateTimeOffset
. It is a much better choice than DateTime
[8].
Testing
When testing your applications make sure you test countries in each hemisphere, with both DST on and off. Test also transition from Summer Time to Winter Time and boundary cases (UTC+13) and half-hour time zones, at least.
In Conclusion
Finally, I think you should all watch this brilliant video by @computer_phile as he goes down a rabbit hole of frustration trying to implement time zones.
While I think Daylight Savings is useless, unfortunately we still have to make sure that our applications work correctly until the rest of the world discovers that it's useless.
This is usually done twice a year. Check out the Microsoft Daylight Saving Time & Time Zone Blog. ↩︎
Also known as ZoneInfo, TZDB or the TZ Database ↩︎
If you run Active Directory, the Domain Controller having the PDCEmulator FSMO is the time source and should be configured to an external time source. Have a look at Imed Boukhaf's Blog Post on Time Configuration in Active Directory. ↩︎
Kerberos uses them to protect against replay attacks—where an authentication packet is intercepted on the network and then resent later to authenticate on the original sender's behalf. ↩︎
The allowed time skew can be configured using the Maximum tolerance for computer clock synchronization GPO setting (located in the Computer Configuration\Windows Settings\Security Settings\Account Policies\Kerberos Policy GPO container). It determines the maximum time skew (in minutes) that Windows will tolerate between client and a server clocks in a Windows Kerberos environment. Setting the time skew too high creates a higher risk for replay attacks. ↩︎
For a more detailed explanation check out Lau Taarnskov's brilliant blog post on this topic. ↩︎
For more information check out the "What's wrong with DateTime anyway?" blog post by Noda Time. ↩︎