- There are 23, 24 or 25 hours on one day (daylight saving time change days)
- An hour has 60 minutes.
- A minute has 60, 61 or 62 seconds (leap seconds).
- A day has 1380, 1440 or 1500 minutes.
- A week has 7 days.
- A day has 82800, 86400, 86401, 86402 or 90000 seconds.
- A month has 28, 29, 30 or 31 days. In some systems, a month is standardized to be 30 days.
- A year has 365 or 366 days, but in some systems, it's standardized to be 360 days.
- A year has 52 or 53 weeks.
- Even though we have an ISO standard for weeks, end users don't agree on the starting weekday for a week.
- Some dates don't exist, and for historical dates, the offset between different geographical regions was not about hours, but about days. The russian October Revolution actually happened in November, according to most European calendars of that time, but it was October in Russia.
- This is all about the Christian calendar. There are other calendars out there...
- Local time deviates from UTC time in a number of hours, which can be fractional in some rare cases
- For all practical purposes, GMT is the same as UTC, and GMT is not the local time of London (London uses GMT+1 in the summer).
- UTC time offset is a function that takes the UTC time stamp and geographical location as parameter, and UTC time offset is often historically different for two different cities in the same country.
- A time zone can be specifed using a GMT offset, just like time stamps.
- A time zone can include several regions with different daylight saving rules.
- A floating point number indicating the number of days since a specific date at midnight
- An integer or floating point number indicating the number of seconds since a specific date at midnight
- Year, Month, Day, Hour, Minutes, Seconds as separate values
UTC time offsets are usually specified this way:
- Number of hours difference between the local time and UTC, at the time of the timestamp
- Geographic location (like 'Europe/Copenhagen')
- Time zone (like 'CET')
- The internal clock of the PC uses local time, and changes. If you use virtualization or dual-boot, you may risk that it changes twice, giving incorrect time.
- The internal clock of the PC uses UTC time, and does not change.
- Daylight saving time is usually handled using locally stored information, which may get outdated, so that the computer actually miscalculates the time by one hour.
- They're implemented nicely, and the software needs to know about them.
- They're not implemented, so the software doesn't need to know about them, but instead, the clock is adjusted, and the software needs to be capable of handling a clock that doesn't move for 1-2 seconds.
- Most PCs today have some kind of clock synchronization over the internet, which yields a sub-second precision. However, don't count on your clock to be 1ms precise.
- PCs often have their clocks adjusted, so that you need to make sure that your software can survive a clock, that moves backwards.
What about statistics? Here you have a lot of other problems:
- Total numbers per month don't make sense for February, which changes it's length every 4 years.
- Numbers per day, for a month usually don't make sense either, because the number of weekend days in a month is varying, and numbers often depend on weekdays.
- Comparing. If you have two timestamps from different sources, you need to define many things to be able to say timestamp1=timestamp2.
- Round-off errors often mean, that timestamp1+timeinterval-timeinterval<>timestamp1. When you have deadlines, it can become very tricky to decide, if a deadline has been reached, or not.
- Uniqueness of timestamps: Some programmers want to use timestamps as primary key. Some database systems even support that, but what happens when you transport these timestamps to other parts of your software, will they still be unique?
- Many people don't understand the difference between GMT offsets for time zones and time stamps. Example: In Denmark, which is located in the GMT+1 time zone, we use GMT+2 time stamps during the summer.
- Terms like "CET" have many meanings, depending on who you ask. It can be the time in Germany in winter, it can be the current time in Germany, and it can describe the time zone which includes France and Germany, which did not have the same daylight saving time rules 30 years ago. In case of the "CET time zone", a historical timestamp may be useless without knowing if it applies to a location in France or Germany.
In Windows, the standard functions to convert between local time and UTC time do not handle historical timestamps well, but documentation isn't good at explaining that. On Windows, you should always make days 24 hours and 86400 seconds, and always use local time, unless you really know what you're doing.
Here are some examples of bad time related functionality:
- DateTime.IsDaylightSavingTime Method - The text says "Indicates whether this instance of DateTime is within the Daylight Saving Time range for the current time zone.", but what if there are two different daylight saving time ranges for the time zone? The problem is, that the documentation sets time zone = daylight saving time rule set.
- GetDynamicTimeZoneInformation - The information returned by this information can be invalid just after returning. This function basically doesn't make sense, it should have taken a time stamp as parameter.
- TimeZone.GetUtcOffset Method - It calculates the UTC offset from the local time. However, once a year, the same local time repeats itself for one hour, with two different UTC offsets. So this method doesn't make sense.
Linux works very differently - it counts seconds everywhere and uses geographic locations for GMT offset calculcations. This works extremely well, and Linux only converts to year/month/day representations when interacting with the user. However, even though linux can support leap seconds, most apps probably won't work well if you enable it.
This blog post doesn't cover all the kinds of trouble we programmers face, there's much more. My advice is to try to keep things simple and prepare for the worst.