2

This question is specifically about future dates and times (for past values UTC is undoubtedly the first choice).


I'd wonder if anybody had a suggestion as to the "best" way to save a future date and time in a MySQL database (or for that matter also generally), particularly in a context where the column can hold times from different timezones. Considering that timezone rules may change UTC might not be the best option.

The most feasible option I found so far would be the save it as text in the location's local time, together with the location (eg. "America/*"). Unfortunately this solution might be more prone to data corruption and is definitely less convenient for calculations.

Could anybody think of something better?

Thanks in advance

  • 1
    "Considering that timezone rules may change UTC might not be the best option" -- I can't follow your logic. Arbitrary time zone legislations are precisely an argument for UTC. – Álvaro González Apr 22 '17 at 12:51
  • 3
    @ÁlvaroGonzález - it's not as simple as that. If an event is at 10 AM on July 1st in Cairo Egypt in year 2027, I cannot tell you right now what UTC time that will be, since that would require an assumption on my part that the Egyptian government won't change their time zone rules between now and then. Indeed, this has been a problem in the past [with Egypt in particular](http://codeofmatt.com/2016/07/01/time-zone-chaos-inevitable-in-egypt/), and [other time zones with some regularity](http://codeofmatt.com/2016/04/23/on-the-timing-of-time-zone-changes/). – Matt Johnson-Pint Apr 24 '17 at 01:34

2 Answers2

5

First, I've written about this in extensive detail before, so please read my answers here and here, as well as this blog post by Lau Taarnskov.

With specific regard to MySQL, you generally don't want to use a TIMESTAMP field for the local time of a future event, as it will convert from the session's time zone to UTC at write time, and convert back from UTC to the session's time zone at read time. Even if these are the same time zone ids (which they don't have to be), there's no guarantee that the time zone data won't change for one or both of the time zones between when you write the data and when the event takes place.

Instead, use a DATETIME field, which does no implicit time zone conversions. You get the exact value out that you wrote. Store the local time of the event, and store a VARCHAR field containing the time zone identifier for the event. This is the only way to retain the user's original intent.

Rationale and edge cases are all described in the answers I gave previously.

Community
  • 1
  • 1
Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
2

The considerations for saving future datestamps are pretty much the same as for past datestamps.

(I call them datestamps because both DATETIME and TIMESTAMP are reserved words in MySQL. For the sake of discussion I want a word that doesn't imply either data type.)

If you're building a system to be used by people in multiple time zones, it's a good idea to ask each user for her time zone preference, and store it in her user profile. Then, when she logs in you can retrieve it, then do

  SET time_zone = 'America/Halifax'

or whatever, naming the user's time zone preference.

If your MySQL server is running on a Linux, BSD, or other *nix system, these time zones come from the zoneinfo subsystem on that machine. zoneinfo gets updated when various national jurisdictions change time zone rules. The people who maintain popular distros routinely push updates to zoneinfo, so you'll be reasonably up to date. (If your MySQL server is running on a Windows host, do some reading about MySQL time zone stuff on that OS. It's more of a hassle to keep things up to date.)

Then, if you use TIMESTAMP data types for your datestamps, any time you retrieve a value, it is automatically translated from UTC to the local timezone before display. Any time you store a value it is automatically translated to UTC. The NOW() value is timestamp-like in this respect. So if you, for example, do

 UPDATE appointment
    SET datestamp = NOW() + INTERVAL 7 DAY
  WHERE id = something

you'll store a UTC time that's a week after this moment. Then if you do

SELECT datestamp
  FROM appointment
 WHERE id = something

the user will see the time in her local timezone as set with SET timezone.

If you use DATETIME data types for your datestamps, you can offset them yourself when you store and retrieve them. When you store them, offset them from the local timezone to UTC. When you retrieve them, go the other way. Use CONVERT_TZ() for that.

 UPDATE appointment 
    SET datestamp = CONVERT_TZ(NOW(), 'America/Halifax', 'UTC') + INTERVAL 7 DAY
  WHERE id = something

SELECT CONVERT_TZ(datestamp, 'UTC', 'America/Halifax') datestamp
  FROM appointment
 WHERE id = something

Obviously, substitute your user's choice of timezone for 'America/Halifax' in these queries.

IF YOU POSSIBLY CAN AVOID IT don't store your datestamps with reference to a local time that changes from daylight savings to standard time. If you do that, you will have ongoing glitches on the changeover days for the lifetime of your application. I know this because I've inherited a couple of systems that worked that way. Bad idea. UTC: good idea.

O. Jones
  • 103,626
  • 17
  • 118
  • 172
  • 1
    It isn't common to see such clear and flawless explanations about time handling. – Álvaro González Apr 22 '17 at 12:53
  • 1
    I say that `DATETIME` is like taking a picture of a clock; you can't tell what TZ is involved. – Rick James Apr 22 '17 at 18:32
  • 1
    That's a great way to put it. Trouble is, `TIMESTAMP`s run out in early 2038 unless they change the on-disk format. – O. Jones Apr 22 '17 at 20:48
  • @ÁlvaroGonzález - Unfortunately, this answer is not clear and flawless. It gives a good description of `TIMESTAMP` vs `DATETIME`, but it doesn't address the problem at hand. – Matt Johnson-Pint Apr 24 '17 at 01:58
  • 1
    @O.Jones - UTC is not appropriate for scheduling of future events. Sorry, but any advice to the contrary is flawed. In particular, your last statement to avoid non-dst time zones means one shouldn't schedule events in most of the US or Europe. – Matt Johnson-Pint Apr 24 '17 at 02:00
  • Huh. So, if I want to schedule a meeting in the future with a colleague in Europe and another in India, how should I represent the time in a way that makes sense to them all? If I want to schedule the expiration of a subscription, how should I represent that moment in time? With respect, your statement "flawed" needs some justification. As for my advice about avoiding setting an application's DBMS time to local time in a zone that changes over, I stand by that advice. – O. Jones Apr 24 '17 at 18:12