I keep hearing people advise each other to store timestamps in UTC. There is usually no good reason to use UTC over any other time zone, as long as you pick one. Once a time stamp is associated with a time zone, you can convert back and forth, and most of the time, software does that for you. Putting an emphasis on UTC at storage is pointless and forces the engineers to handle time zone plumbing themselves or at least do mental arithmetics that aren't necessary.
In Python for example, both datetime.now() and datetime.utcnow() return a datetime object lacking time zone information. The latter function is the most explicit of the two, but neither associate a time zone object with their response.
>>> from datetime import datetime >>> datetime.now() datetime.datetime(2019, 8, 24, 12, 35, 10, 844654) >>> datetime.utcnow() datetime.datetime(2019, 8, 24, 16, 35, 13, 95068)
I would argue that having foundational parts of the standard library returning time zone-dumb objects is a reason why so many people struggle with time when they want to go beyond "Hello world". Let's consider a parallel universe where the above functions are returning objects that are time zone aware.
>>> from datetime import datetime >>> datetime.now() datetime.datetime(2019, 8, 24, 12, 35, 10, 844654, tz="US/Eastern") >>> datetime.utcnow() datetime.datetime(2019, 8, 24, 16, 35, 13, 95068, tz="UTC")
What's the difference? If you store or transfer the timestamp in the first example, a user or system trying to interpret that data has no idea whether that time stamp is 12:35 in New York, Paris or Moscow. That system will no be able to compare that timestamp to others. In the second example, storing the timestamp with a time zone will allow anyone who reads it to get some context about where the timestamp occurred, but most importantly, to make sense of that timestamp in relation to others (e.g. did this event occur before or after this other event) no matter where in the world they were created.
Using UTC everywhere for storage and transfer is an attempt at solving the issue above by defining a time zone, but always use the same one. The problem is that most frameworks will already do that for you if you give them a time zone aware timestamp and choose the right date types. Telling engineers to use UTC without first explaining why, is producing cargo cult behaviors, you see columns with seconds since UNIX epoch or worse, time zone dumb timestamps and assume that timestamp is UTC. This behavior cripples the tools made available by the databases and frameworks. A good example of a tool with the right data types and a client that does the right thing (TM) is PostgreSQL.
postgres=# SET TIMEZONE = 'US/Eastern';
SET
postgres=# SELECT '2019-08-24T13:25:40-04:00'::timestamptz;
timestamptz
------------------------
2019-08-24 13:25:40-04
postgres=# SELECT '2019-08-24T17:25:40-00:00'::timestamptz;
timestamptz
------------------------
2019-08-24 13:25:40-04
Your session has a time zone defined and all timestamps with time zone are automatically translated to that time zone. There are a few gotchas, but the general behavior is predictable and easy to get right if you only use the right date types.
Here is a sample application written using PostgreSQL, Python 3 and JavaScript using the moments library. Note that I refrain from mentioning a time zone at any point, however the timestamp will be displayed properly no matter where they are created and no matter where they are displayed. I do not have to convert anything because I am using time zone aware data structures and I am trusting the frameworks to do the right thing.
Type your name and hit the "send" button below, this will:
| name | frontend | timezone | python | postgres |
|---|---|---|---|---|
| blablabla |
August 24th, 1:24:47 pm 2019-08-24T13:25:40-04:00 |
US/Eastern |
August 24th, 1:24:47 pm 2019-08-24T13:25:40-04:00 |
August 24th, 1:24:47 pm 2019-08-24T13:25:40-04:00 |
Note that I purposedly deployed the Python API with a French time zone, in France, and deployed the database in Japan, with a Japanese time zone to make things more fun and add some delay. The three timestamps will come back from the API (frontend, api and database) encoded in ISO8601, each with their own respective time zones and will be decoded by the Moments libray which will display them on your screen. Moments automatically uses your local time zone to display that time. The three formatted time stamps will be very close to each other, accounting for the request delays, and the ISO8601 timestamps will show the respective time zones.
In conclusion, I didn't have to do anything special to make the respective frameworks understand each others time zones, I'm using a standard encoding for time (ISO8601) for all transfers and I'm trusting the right data types. Handling time is very similar to character set encoding, if everything is unicode/time zoned, it's easy, when you have to use bytes for transfers, use a standard encoding (UTF-8 for characters, ISO8601 for time stamps). You should do the same.