What Timezone Does MySQL's Now() Follow

What timezone does MySQL's NOW() follow

It's in the current time zone. From the 5.1 docs:

Returns the current 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.
The value is expressed in the current
time zone.

Now "the current time zone" can mean different things:

  • The system time zone
  • A time zone specified for the MySQL server in general
  • A connection-specific time zone

More details are in the 5.1 time zone documentation.

(The 5.4 docs look the same for these bits. Obviously consult the docs for the version you're running for the best possible information.)

How do I get the current time zone of MySQL?

From the manual (section 9.6):

The current values of the global and client-specific time zones can be retrieved like this:

mysql> SELECT @@global.time_zone, @@session.time_zone;

Edit The above returns SYSTEM if MySQL is set to use the system's timezone, which is less than helpful. Since you're using PHP, if the answer from MySQL is SYSTEM, you can then ask the system what timezone it's using via date_default_timezone_get. (Of course, as VolkerK pointed out, PHP may be running on a different server, but as assumptions go, assuming the web server and the DB server it's talking to are set to [if not actually in] the same timezone isn't a huge leap.) But beware that (as with MySQL), you can set the timezone that PHP uses (date_default_timezone_set), which means it may report a different value than the OS is using. If you're in control of the PHP code, you should know whether you're doing that and be okay.

But the whole question of what timezone the MySQL server is using may be a tangent, because asking the server what timezone it's in tells you absolutely nothing about the data in the database. Read on for details:

Further discussion:

If you're in control of the server, of course you can ensure that the timezone is a known quantity. If you're not in control of the server, you can set the timezone used by your connection like this:

set time_zone = '+00:00';

That sets the timezone to GMT, so that any further operations (like now()) will use GMT.

Note, though, that time and date values are not stored with timezone information in MySQL:

mysql> create table foo (tstamp datetime) Engine=MyISAM;
Query OK, 0 rows affected (0.06 sec)

mysql> insert into foo (tstamp) values (now());
Query OK, 1 row affected (0.00 sec)

mysql> set time_zone = '+01:00';
Query OK, 0 rows affected (0.00 sec)

mysql> select tstamp from foo;
+---------------------+
| tstamp |
+---------------------+
| 2010-05-29 08:31:59 |
+---------------------+
1 row in set (0.00 sec)

mysql> set time_zone = '+02:00';
Query OK, 0 rows affected (0.00 sec)

mysql> select tstamp from foo;
+---------------------+
| tstamp |
+---------------------+
| 2010-05-29 08:31:59 | <== Note, no change!
+---------------------+
1 row in set (0.00 sec)

mysql> select now();
+---------------------+
| now() |
+---------------------+
| 2010-05-29 10:32:32 |
+---------------------+
1 row in set (0.00 sec)

mysql> set time_zone = '+00:00';
Query OK, 0 rows affected (0.00 sec)

mysql> select now();
+---------------------+
| now() |
+---------------------+
| 2010-05-29 08:32:38 | <== Note, it changed!
+---------------------+
1 row in set (0.00 sec)

So knowing the timezone of the server is only important in terms of functions that get the time right now, such as now(), unix_timestamp(), etc.; it doesn't tell you anything about what timezone the dates in the database data are using. You might choose to assume they were written using the server's timezone, but that assumption may well be flawed. To know the timezone of any dates or times stored in the data, you have to ensure that they're stored with timezone information or (as I do) ensure they're always in GMT.

Why is assuming the data was written using the server's timezone flawed? Well, for one thing, the data may have been written using a connection that set a different timezone. The database may have been moved from one server to another, where the servers were in different timezones (I ran into that when I inherited a database that had moved from Texas to California). But even if the data is written on the server, with its current time zone, it's still ambiguous. Last year, in the United States, Daylight Savings Time was turned off at 2:00 a.m. on November 1st. Suppose my server is in California using the Pacific timezone and I have the value 2009-11-01 01:30:00 in the database. When was it? Was that 1:30 a.m. November 1st PDT, or 1:30 a.m. November 1st PST (an hour later)? You have absolutely no way of knowing. Moral: Always store dates/times in GMT (which doesn't do DST) and convert to the desired timezone as/when necessary.

Should MySQL have its timezone set to UTC?

It seems that it does not matter what timezone is on the server as long as you have the time set right for the current timezone, know the timezone of the datetime columns that you store, and are aware of the issues with daylight savings time.

On the other hand if you have control of the timezones of the servers you work with then you can have everything set to UTC internally and never worry about timezones and DST, at least when it comes to storing internal time.

Here are some notes I collected of how to work with timezones as a form of cheatsheet for myself and others which might influence what timezone the person will choose for his/her server and how he/she will store date and time.

MySQL Timezone Cheatsheet

Notes:

  1. Changing the timezone will not change the stored datetime or
    timestamp
    , but it will select a different datetime from
    timestamp columns

  2. Warning! UTC has leap seconds, these look like '2012-06-30 23:59:60' and can
    be added randomly, with 6 months prior notice, due to the slowing of
    the earths rotation

  3. GMT confuses seconds, which is why UTC was invented.

  4. Warning! different regional timezones might produce the same datetime value due
    to daylight savings time

  5. The timestamp column only supports dates 1970-01-01 00:00:01 to 2038-01-19 03:14:07 UTC, due to a limitation.

  6. Internally a MySQL timestamp column is stored as UTC but
    when selecting a date MySQL will automatically convert it to the
    current session timezone.

    When storing a date in a timestamp, MySQL will assume that the date
    is in the current session timezone and convert it to UTC for
    storage.

  7. MySQL can store partial dates in datetime columns, these look like
    "2013-00-00 04:00:00"

  8. MySQL stores "0000-00-00 00:00:00" if you set a datetime column as
    NULL, unless you specifically set the column to allow null when you
    create it.

  9. Read this

To select a timestamp column in UTC format

no matter what timezone the current MySQL session is in:

SELECT 
CONVERT_TZ(`timestamp_field`, @@session.time_zone, '+00:00') AS `utc_datetime`
FROM `table_name`

You can also set the sever or global or current session timezone to UTC and then select the timestamp like so:

SELECT `timestamp_field` FROM `table_name`

To select the current datetime in UTC:

SELECT UTC_TIMESTAMP();
SELECT UTC_TIMESTAMP;
SELECT CONVERT_TZ(NOW(), @@session.time_zone, '+00:00');

Example result: 2015-03-24 17:02:41

To select the current datetime in the session timezone

SELECT NOW();
SELECT CURRENT_TIMESTAMP;
SELECT CURRENT_TIMESTAMP();

To select the timezone that was set when the server launched

SELECT @@system_time_zone;

Returns "MSK" or "+04:00" for Moscow time for example, there is (or was) a MySQL bug where if set to a numerical offset it would not adjust the Daylight savings time

To get the current timezone

SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP);

It will return 02:00:00 if your timezone is +2:00.

To get the current UNIX timestamp (in seconds):

SELECT UNIX_TIMESTAMP(NOW());
SELECT UNIX_TIMESTAMP();

To get the timestamp column as a UNIX timestamp

SELECT UNIX_TIMESTAMP(`timestamp`) FROM `table_name`

To get a UTC datetime column as a UNIX timestamp

SELECT UNIX_TIMESTAMP(CONVERT_TZ(`utc_datetime`, '+00:00', @@session.time_zone)) FROM `table_name`

Get a current timezone datetime from a positive UNIX timestamp integer

SELECT FROM_UNIXTIME(`unix_timestamp_int`) FROM `table_name`

Get a UTC datetime from a UNIX timestamp

SELECT CONVERT_TZ(FROM_UNIXTIME(`unix_timestamp_int`), @@session.time_zone, '+00:00') 
FROM `table_name`

Get a current timezone datetime from a negative UNIX timestamp integer

SELECT DATE_ADD('1970-01-01 00:00:00',INTERVAL -957632400 SECOND) 

There are 3 places where the timezone might be set in MySQL:

Note: A timezone can be set in 2 formats:

  1. an offset from UTC: '+00:00', '+10:00' or '-6:00'
  2. as a named time zone: 'Europe/Helsinki', 'US/Eastern', or 'MET'

Named time zones can be used only if the time zone information tables
in the mysql database have been created and populated.

in the file "my.cnf"

default_time_zone='+00:00'

or

timezone='UTC'

@@global.time_zone variable

To see what value they are set to

SELECT @@global.time_zone;

To set a value for it use either one:

SET GLOBAL time_zone = '+8:00';
SET GLOBAL time_zone = 'Europe/Helsinki';
SET @@global.time_zone='+00:00';

@@session.time_zone variable

SELECT @@session.time_zone;

To set it use either one:

SET time_zone = 'Europe/Helsinki';
SET time_zone = "+00:00";
SET @@session.time_zone = "+00:00";

both "@@global.time_zone variable" and "@@session.time_zone variable" might return "SYSTEM" which means that they use the timezone set in "my.cnf".

For timezone names to work (even for default-time-zone) you must setup your timezone information tables need to be populated: http://dev.mysql.com/doc/refman/5.1/en/time-zone-support.html

Note: you can not do this as it will return NULL:

SELECT 
CONVERT_TZ(`timestamp_field`, TIMEDIFF(NOW(), UTC_TIMESTAMP), '+00:00') AS `utc_datetime`
FROM `table_name`

Setup mysql timezone tables

For CONVERT_TZ to work, you need the timezone tables to be populated

SELECT * FROM mysql.`time_zone` ;
SELECT * FROM mysql.`time_zone_leap_second` ;
SELECT * FROM mysql.`time_zone_name` ;
SELECT * FROM mysql.`time_zone_transition` ;
SELECT * FROM mysql.`time_zone_transition_type` ;

If they are empty, then fill them up by running this command

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql

if this command gives you the error "data too long for column 'abbreviation' at row 1", then it might be caused by a NULL character being appended at the end of the timezone abbreviation

the fix being to run this

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql
(if the above gives error "data too long for column 'abbreviation' at row 1")
mysql_tzinfo_to_sql /usr/share/zoneinfo > /tmp/zut.sql

echo "SET SESSION SQL_MODE = '';" > /tmp/mysql_tzinfo_to.sql
cat /tmp/zut.sql >> /tmp/mysql_tzinfo_to.sql

mysql --defaults-file=/etc/mysql/my.cnf --user=verifiedscratch -p mysql < /tmp/mysql_tzinfo_to.sql

(make sure your servers dst rules are up to date zdump -v Europe/Moscow | grep 2011 https://chrisjean.com/updating-daylight-saving-time-on-linux/)

See the full DST (Daylight Saving Time) transition history for every timezone

SELECT 
tzn.Name AS tz_name,
tztt.Abbreviation AS tz_abbr,
tztt.Is_DST AS is_dst,
tztt.`Offset` AS `offset`,
DATE_ADD('1970-01-01 00:00:00',INTERVAL tzt.Transition_time SECOND) AS transition_date
FROM mysql.`time_zone_transition` tzt
INNER JOIN mysql.`time_zone_transition_type` tztt USING(Time_zone_id, Transition_type_id)
INNER JOIN mysql.`time_zone_name` tzn USING(Time_zone_id)
-- WHERE tzn.Name LIKE 'Europe/Moscow' -- Moscow has weird DST changes
ORDER BY tzt.Transition_time ASC

CONVERT_TZ also applies any necessary DST changes based on the rules in the above tables and the date that you use.

Note:

According to the docs, the value you set for time_zone does not change, if you set it as "+01:00" for example, then the time_zone will be set as an offset from UTC, which does not follow DST, so it will stay the same all year round.

Only the named timezones will change time during daylight savings time.

Abbreviations like CET will always be a winter time and CEST will be summer time while +01:00 will always be UTC time + 1 hour and both won't change with DST.

The system timezone will be the timezone of the host machine where mysql is installed (unless mysql fails to determine it)

You can read more about working with DST here

When not to use UTC by the legendary Jon Skeet: https://codeblog.jonskeet.uk/2019/03/27/storing-utc-is-not-a-silver-bullet/
(For example a scheduled event in the future that represents a time, not an instant in time)

related questions:

  • How do I set the time zone of MySQL?
  • MySql - SELECT TimeStamp Column in UTC format
  • How to get Unix timestamp in MySQL from UTC time?
  • Converting Server MySQL TimeStamp To UTC
  • https://dba.stackexchange.com/questions/20217/mysql-set-utc-time-as-default-timestamp
  • How do I get the current time zone of MySQL?
  • MySQL datetime fields and daylight savings time -- how do I reference the "extra" hour?
  • Converting negative values from FROM_UNIXTIME

Sources:

  • https://bugs.mysql.com/bug.php?id=68861
  • http://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html
  • http://dev.mysql.com/doc/refman/5.1/en/datetime.html
  • http://en.wikipedia.org/wiki/Coordinated_Universal_Time
  • http://shafiqissani.wordpress.com/2010/09/30/how-to-get-the-current-epoch-time-unix-timestamp/
  • https://web.ivy.net/~carton/rant/MySQL-timezones.txt

Set timezone for MYSQL NOW()

Your question is not clear but if you want to change date and time value from UTC to your time zone, you can use

CONVERT_TZ(date, 'UTC',  'Asia/Kolkata')

You can select the UTC date and time value in your time zone:

SELECT CONVERT_TZ(date, 'UTC',  'Asia/Kolkata') AS local FROM table

If CONVERT_TZ function does not work, you need to install time zones (time zones should be already stored in MySQL). One note is that you need to store UTC value in your database and later convert to whatever time zone you want.

MySQL now() change timezone

You would want to go ahead and use the CONVERT_TZ() function in MySQL. It's based off the Olson database which your operating system uses.

Here is the documentation.

MySQL Time Zones

From the MySQL 5.7 documentation (emphasis mine):

timezone values can be given in several formats, none of which are
case sensitive:

The value 'SYSTEM' indicates that the time zone should be the same as
the system time zone.

The value can be given as a string indicating an offset from UTC, such
as '+10:00' or '-6:00'.

The value can be given as a named time zone, such as
'Europe/Helsinki', 'US/Eastern', or 'MET'. Named time zones can be
used only if the time zone information tables in the mysql database
have been created and populated.

It should be noted that the MySQL timezone variable's default setting is SYSTEM at MySQL startup. The SYSTEM value is obtained from an operating system setting (e.g. from the file that is referenced by the symlink /etc/localtime)

MySQL's default timezone variable can be initialised to a different value at start-up by providing the following command line option:

--default-time-zone=timezone

Alternatively, if you are supplying the value in an options file, you should use the following syntax to set the variable:

--default-time-zone='timezone'

If you are a MySQL SUPER user, you can set the SYSTEM time_zone variable at runtime from the MYSQL> prompt using the following syntax:

SET GLOBAL time_zone=timezone;

MySQL also supports individual SESSION timezone values which defaults to the GLOBAL time_zone environment variable value. To change the session timezone value during a SESSION, use the following syntax:

SET time_zone=timezone;

In order to interrogate the existing MYSQL timezone setting values, you can execute the following SQL to obtain these values:

SELECT @@global.time_zone, @@session.time_zone;

For what it's worth, I simply googled mysql time_zone configuration valid values and looked at the first result.

How do I make MySQL's NOW() and CURDATE() functions use UTC?

Finally found what I was looking for...

In my.cnf,

[mysqld_safe]
timezone = UTC

I was putting this option under [mysqld], and mysql was failing to start.

Calling "SET time_zone='+0:00';" on every page load would also work, but I don't like the idea of calling that query on every single page load.



Related Topics



Leave a reply



Submit