web-dev-qa-db-ja.com

MySQLのタイムゾーンをUTCに設定する必要がありますか?

https://serverfault.com/questions/191331/should-servers-have-their-timezone-set-to-gmt-utc の質問をフォローする

MySQLのタイムゾーンをUTCに設定する必要がありますか?それともサーバーと同じタイムゾーンに設定する必要がありますか?それともPHPを設定しますか? (UTCではない場合)

長所と短所は何ですか?

130
Timo Huovinen

現在のタイムゾーンに合わせて時間を設定し、保存している日時列のタイムゾーンを知っていて、夏時間に関する問題を認識していれば、サーバー上のタイムゾーンは関係ありません。

一方、使用するサーバーのタイムゾーンを管理している場合は、すべて内部的にUTCに設定し、タイムゾーンとDSTを心配することはありません。

ここに私自身がチートシートの形でタイムゾーンを使用する方法と、その人が自分のサーバーにどのタイムゾーンを選択するか、そして日付と時刻を保存する方法に影響を与える可能性があるその他について説明しました。

MySQLタイムゾーンチートシート

ノート:

  1. タイムゾーンを変更しても、保存されている日時またはタイムスタンプは変更されませんが、タイムスタンプ列から異なる日時が選択されます。
  2. 警告!UTCにはうるう秒がありますが、これらは「2012-06-30 23:59:60」のように見え、6か月前にランダムに追加できます。地球の回転が遅いため
  3. GMTは秒を混同します、それはUTCが発明された理由です。

  4. 警告!夏時間のため、異なる地域のタイムゾーンで同じdatetime値が生成される場合があります

  5. タイムスタンプ列は、日付の1970-01-01 00:00:01から2038-01-19 03:14:07 UTCのみをサポートします。これは 制限 が原因です。
  6. 内部的には MySQLタイムスタンプカラムUTC として保存されますが、日付を選択するとMySQLは自動的にそれを現在のセッションタイムゾーンに変換します。

    タイムスタンプに日付を格納するとき、MySQLはその日付が現在のセッションタイムゾーンにあると見なし、それをUTCに変換して格納します。

  7. MySQLはdatetimeカラムに部分的な日付を格納することができ、これらは "2013-00-00 04:00:00"のように見えます
  8. あなたがそれを作成するときにNULLを許可するようにあなたが列を特別に設定しない限り、あなたがNULLとしてdatetimeカラムを設定するならば、MySQLは "0000-00-00 00:00:00"を格納します。
  9. これを読む

UTC形式のタイムスタンプ列を選択するには

現在のMySQLセッションがどのタイムゾーンにあるかに関係なく、

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

また、サーバーのタイムゾーンまたはグローバルまたは現在のセッションのタイムゾーンをUTCに設定してから、次のようにタイムスタンプを選択することもできます。

SELECT `timestamp_field` FROM `table_name`

UTCで現在の日時を選択するには:

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

結果の例:2015-03-24 17:02:41

セッションタイムゾーンで現在の日時を選択するには

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

サーバーの起動時に設定されたタイムゾーンを選択する

SELECT @@system_time_zone;

たとえばモスクワ時間の場合は "MSK"または "+04:00"を返します。数値オフセットに設定した場合は夏時間を調整できないというMySQLのバグがあります(またはありました)。

現在のタイムゾーンを取得する

SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP);

あなたのタイムゾーンが+2:00の場合、それは02:00:00を返します。

現在のUNIXタイムスタンプを取得するには(秒単位):

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

タイムスタンプ列をUNIXタイムスタンプとして取得する

SELECT UNIX_TIMESTAMP(`timestamp`) FROM `table_name`

UTC日時列をUNIXタイムスタンプとして取得するには

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

正のUNIXタイムスタンプ整数から現在のタイムゾーンの日時を取得する

SELECT FROM_UNIXTIME(`unix_timestamp_int`) FROM `table_name`

UNIXのタイムスタンプからUTCの日時を取得する

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

負のUNIXタイムスタンプ整数から現在のタイムゾーンの日時を取得します。

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

MySQLでタイムゾーンが設定される場所は3箇所あります。

注:タイムゾーンは2つの形式で設定できます。

  1. uTCからのオフセット: '+00:00'、 '+ 10:00'、または '-6:00'
  2. 名前付きのタイムゾーンとして: 'Europe/Helsinki'、 'US/Eastern'、または 'MET'

名前付きタイムゾーンは、mysqlデータベースのタイムゾーン情報テーブルが作成されてデータが入力されている場合にのみ使用できます。

ファイル "my.cnf"内

default_time_zone='+00:00'

または

timezone='UTC'

@@ global.time_zone変数

どのような値に設定されているかを見る

SELECT @@global.time_zone;

値を設定するには、次のいずれかを使用します。

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

@@ session.time_zone変数

SELECT @@session.time_zone;

設定するには、どちらかを使用します。

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

"@@ global.time_zone変数"と "@@ session.time_zone変数"の両方が "SYSTEM"を返す可能性があります。これは、 "my.cnf"で設定されたタイムゾーンを使用することを意味します。

タイムゾーン名を機能させるには(default-time-zoneでも)タイムゾーン情報テーブルを設定する必要があります。http: //dev.mysql.com/doc/refman/5.1/en/time-zone-support.html

注意:NULLを返すのでこれはできません。

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

MySQLタイムゾーンテーブルの設定

CONVERT_TZが機能するためには、移入されるタイムゾーンテーブルが必要です。

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` ;

空の場合は、このコマンドを実行して埋めます。

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

このコマンドでエラー " 1行目の列 '省略形'にはデータが長すぎます "が表示される場合は、タイムゾーンの省略形の最後にNULL文字が追加されている可能性があります。

これを実行するための修正

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

(あなたのサーバーのDSTルールが最新のものであることを確認してくださいzdump -v Europe/Moscow | grep 2011https://chrisjean.com/updating-daylight-saving-time-on-linux/

すべてのタイムゾーンのDST(サマータイム)移行履歴をすべて表示

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は、上記の表の規則と使用した日付に基づいて、必要なDSTの変更も適用します。

注:
docs によると、time_zoneに設定した値は変更されません。たとえば、 "+ 01:00"に設定すると、time_zoneがオフセットとして設定されます。 DSTに従わないUTCから、それは一年中同じままになります。

名前付き timezones だけが夏時間の間に時間を変更します。

CETのような省略形は常に冬時間、CESTは夏時間、+ 01:00は常にUTC時間+ 1時間で、どちらもDSTで変わりません。

systemタイムゾーンは、mysqlがインストールされているホストマシンのタイムゾーンになります(mysqlがそれを決定できない場合を除く)。

DSTを使った作業についてもっと読むことができます ここ

関連する質問

出典:

471
Timo Huovinen

これは実用的な例です。

jdbc:mysql://localhost:3306/database?useUnicode=yes&characterEncoding=UTF-8&serverTimezone=Europe/Moscow
2
tatka

PHPとMySQLには独自のデフォルトのタイムゾーン設定があります。データベースとWebアプリケーションの間で時間を同期させる必要があります。そうしないと、問題が発生する可能性があります。

このチュートリアルを読んでください。 PHPとMySQLタイムゾーンを同期させる方法

2
user1202826

長所と短所はほとんど同じです。それがあなたがこれを望むかどうかによります。

MySQLのタイムゾーンがシステムの時刻と異なる場合(たとえばPHP)、時間を比較したりユーザーと印刷したりすると多少手間がかかる場合があります。

1
alandarev