50

Everywhere I read about converting time to a user's timezone says that the best method is to store a date and time in UTC then just add the user's timezone offset to this time.

How can I store a date in UTC time? I use the MySQL DATETIME field.

When adding a new record to MySQL in my PHP code I would use now() to insert into MySQL DATETIME.

Would I need to use something different than now() to store UTC time?

random
  • 9,774
  • 10
  • 66
  • 83
JasonDavis
  • 48,204
  • 100
  • 318
  • 537
  • 1
    If you go this route, don't forget to account for daylight saving time -- i.e. the timezone offset isn't necessarily constant for a given user's location. – Jim Lewis Aug 28 '09 at 21:01
  • 1
    Yes I have read so many confusing and conflicting things about doing timezones in PHP, it seems to be one the the things php needs to improve – JasonDavis Aug 28 '09 at 21:03
  • 1
    For those who are looking for more info, I link to these fabulous articles: http://infiniteundo.com/post/25326999628/falsehoods-programmers-believe-about-time and http://infiniteundo.com/post/25509354022/more-falsehoods-programmers-believe-about-time-wisdom – Luke H Sep 24 '12 at 18:18

7 Answers7

47

MySQL: UTC_TIMESTAMP()

Returns the current UTC date and time as a value in 'YYYY-MM-DD HH:MM:SS' or YYYYMMDDHHMMSS.uuuuuu format, depending on whether the function is used in a string or numeric context

PHP: gmdate()

Also PHP date_default_timezone_set() is used in PHP to set the current time zone for the script. You can set it to the client time zone so all the formatting functions return the time in his local time.

In truth though I had a hard time getting this to work and always stumble into some gotcha. Eg. time information returned from MySQL is not formatted as 'UTC' so strtotime transforms it into a local time if you are not careful. I'm curious to hear if someone has a reliable solution for this problem, one that doesn't break when dates traverse media boundaries (HTTP->PHP->MySQL and MySQL->PHP->HTTP), also considering XML and RSS/Atom.

Quentin Skousen
  • 1,035
  • 1
  • 18
  • 30
Remus Rusanu
  • 288,378
  • 40
  • 442
  • 569
  • Not sure if anyone got foolproof solution yet! – PC. May 22 '15 at 10:15
  • If my php script gets the UTC time with `gmdate()`, this returns a string. Wouldn't this conflict with setting the field type in MySQL to `DATETIME`? – whatwhatwhat Jan 04 '16 at 03:01
  • @whatwhatwhat what? have a look at the manual https://dev.mysql.com/doc/refman/5.7/en/date-and-time-literals.html – Brad Kent Mar 02 '17 at 04:42
41

I would suggest inserting the date in UTC time zone. This will save you a lot of headaches in the future with daylight saving problems.

INSERT INTO abc_table (registrationtime) VALUES (UTC_TIMESTAMP())

When I query my data I use the following PHP script:

<?php

while($row = mysql_fetch_array($registration)) { 

  $dt_obj = new DateTime($row['message_sent_timestamp'] ." UTC");
  $dt_obj->setTimezone(new DateTimeZone('Europe/Istanbul'));
  echo $formatted_date_long=date_format($dt_obj, 'Y-m-d H:i:s');
}
?>

You can replace the DateTimeZone value with one of the available PHP timezones.

David Newcomb
  • 10,639
  • 3
  • 49
  • 62
Haluk
  • 2,091
  • 2
  • 27
  • 35
  • 2
    +1 But you'll want to escape the timezone literal , i.e., `." \U\T\C"` to avoid any collisions with current of future format characters. – webbiedave May 17 '12 at 18:24
  • 1
    This great solution deals with a timestamp field, but is there a similarly elegant solution if the table stores a date & time from client side? i.e. when storing dateimtes, the datetime literals come from client side (using client's tz). – adbie Nov 17 '12 at 06:02
  • 1
    The `DateTime` constructor accepts a 2nd arg for the timezone. e.g. `$date = new DateTime('2000-01-01', new DateTimeZone('UTC'));` You can keep a static copy of the UTC timezone object somewhere so you don't have to keep re-constructing it. – mpen May 25 '15 at 20:37
  • Adding an answer with some details about how it works and how to insert a date that comes from PHP. – yannick1976 Oct 21 '15 at 17:47
10

NOW() gives you the time (including the timezone offset) of the system running your database. To get UTC date/time you should use UTC_TIMESTAMP() as described in the MySQL Reference Manual.

7

https://dba.stackexchange.com/questions/20217/mysql-set-utc-time-as-default-timestamp

Quoting all the answer from above link in case of delete:

To go along with @ypercube's comment that CURRENT_TIMESTAMP is stored as UTC but retrieved as the current timezone, you can affect your server's timezone setting with the --default_time_zone option for retrieval. This allows your retrieval to always be in UTC.

By default, the option is 'SYSTEM' which is how your system time zone is set (which may or may not be UTC!):

mysql> SELECT @@global.time_zone, @@session.time_zone;
+--------------------+---------------------+
| @@global.time_zone | @@session.time_zone |
+--------------------+---------------------+
| SYSTEM             | SYSTEM              |
+--------------------+---------------------+
1 row in set (0.00 sec)

mysql> SELECT CURRENT_TIMESTAMP();
+---------------------+
| CURRENT_TIMESTAMP() |
+---------------------+
| 2012-09-25 16:28:45 |
+---------------------+
1 row in set (0.00 sec)

You can set this dynamically:

mysql> SET @@session.time_zone='+00:00';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @@global.time_zone, @@session.time_zone;
+--------------------+---------------------+
| @@global.time_zone | @@session.time_zone |
+--------------------+---------------------+
| SYSTEM             | +00:00              |
+--------------------+---------------------+
1 row in set (0.00 sec)

Or permanently in your my.cnf:

[mysqld]
**other variables**
default_time_zone='+00:00'

Restart your server, and you will see the change:

mysql> SELECT @@global.time_zone, @@session.time_zone;
+--------------------+---------------------+
| @@global.time_zone | @@session.time_zone |
+--------------------+---------------------+
| +00:00             | +00:00              |
+--------------------+---------------------+
1 row in set (0.00 sec)

mysql> SELECT CURRENT_TIMESTAMP();
+---------------------+
| CURRENT_TIMESTAMP() |
+---------------------+
| 2012-09-25 20:27:50 |
+---------------------+
1 row in set (0.01 sec)
Community
  • 1
  • 1
TheFrost
  • 1,265
  • 2
  • 15
  • 29
2

As @Haluk suggests, you can store the date as a UTC datetime . I'm complementing his answer for situations when the date you want to insert comes from PHP code, and adding some details about how it works :

$pdo = new PDO('mysql:host=mydbname.mysql.db;dbname=mydbname', 'myusername', 'mypassword');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$insertStmt = $pdo->prepare("insert into test (last_modified)"
    ." values(:last_modified)");
$insertStmt->bindParam(':last_modified', $lastModified, PDO::PARAM_STR);
$lastModified = gmdate("Y-m-d H:i:s");
$insertStmt->execute();

Actually datetime in PHP doesn't have a timezone associated to it. What is passed to PDO is just a string, in one of the formats recognized by MySQL, representing the date in UTC timezone. For example if the date is 2015-10-21 19:32:33 UTC+2:00, the code above just tells MySQL to insert 2015-10-21 17:32:33. gmtdate("Y-m-d H:i:s") gives you the current date in such a format. In any case, all you need to do is build the string representing the date you want to insert in UTC time.

Then, when you read the date, you have to tell PHP that the timezone of the date you just retrieved is UTC. Use the code in Haluk's answer for this.

yannick1976
  • 10,171
  • 2
  • 19
  • 27
0

Random: UTC_TIMESTAMP(6) for time with 6 digits of microseconds.

MySQL 5.7+

Derlin
  • 9,572
  • 2
  • 32
  • 53
Rahim Khoja
  • 695
  • 13
  • 26
0

As per (https://dev.mysql.com/doc/refman/8.0/en/time-zone-support.html) set the timezone upon connection:

SET TIME_ZONE = 'UTC';

After that all datetime functions should be in UTC.

Refrain from using TIMESTAMP() it is not Y2038 save.

theking2
  • 2,174
  • 1
  • 27
  • 36