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


149

/server/191331/should-servers-have-their-timezone-set-to-gmt-utcのフォローアップ質問

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

長所と短所は何ですか?


stackoverflow.com/a/1650406/175071が UTCを使用する正当な理由を共有
Timo Huovinen

UTCはタイムゾーンではありません。UTCは標準、GMTはタイムゾーンです。zachholman.com/talk/utc-is-enough-for-everyone-right
agoldev 2018

回答:


533

現在のタイムゾーンに適切な時刻が設定されていて、格納する日時列のタイムゾーンがわかっていて、夏時間の問題を認識している限り、サーバーのタイムゾーンは問題ではないようです。

一方、使用するサーバーのタイムゾーンを制御できる場合は、すべてを内部でUTCに設定でき、タイムゾーンとDSTについて心配する必要はありません。

ここに、自分用のチートシートの形式としてタイムゾーンを使用する方法について収集したいくつかのメモがあります。その他は、ユーザーがサーバー用に選択するタイムゾーンと、日付と時刻を格納する方法に影響を与える可能性があります。

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

ノート:

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

  4. 警告!夏時間のため、異なる地域のタイムゾーンは同じ日時値を生成する可能性があります

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

    タイムスタンプに日付を保存する場合、MySQLは日付が現在のセッションのタイムゾーンにあると想定し、保存するためにUTCに変換します。

  7. MySQLは部分的な日付を日時列に格納できます。これらは「2013-00-00 04:00:00」のようになります。
  8. 作成時にnullを許可するように列を明示的に設定しない限り、日時列をNULLに設定すると、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 variable"と "@@ session.time_zone variable"の両方が "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の列 'abbreviation'にはデータが長すぎます」というエラーが表示される場合は、タイムゾーンの省略形の末尾に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 2011 https://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 また、上記の表のルールと使用する日付に基づいて、必要な夏時間の変更を適用します。

注:ドキュメント
よると、time_zoneに設定した値は変更されません。たとえば、「+ 01:00」に設定すると、time_zoneはDSTに従わないUTCからのオフセットとして設定されるため、一年中同じです。

名前付きタイムゾーンのみが夏時間の時間を変更します。

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

system(MySQLはそれを決定するために失敗しない限り)タイムゾーンは、MySQLがインストールされているホスト・マシンのタイムゾーンになります

DSTの操作について詳しくは、こちらをご覧ください。

関連する質問:

出典:


したがって、列タイプをタイムスタンプに設定している場合。そして、私のtime_zoneは+12:00で、utcベースの日付/時刻を使用して列を更新したいのですが、updateステートメントにタイムゾーンを含める方法はありますか、またはconvert_tzを使用する必要があります。例えば。更新tableセットmodified= '2016-07-07 08:10 +00:00'
バンパーボックス

2
@bumperbox mysqlは、タイムスタンプ列に指定する日付がmysqlサーバーと同じタイムゾーンにあると常に想定しているため、更新のために+12:00タイムゾーンからmysqlサーバータイムゾーンに日付を変換する必要があります。これが、mysqlサーバーでUTCを使用し、保存する前に日付をUTCに変換する理由です。
Timo Huovinen 16

5
SOを長年使用してきた中で出会った中で最も情報量の多い回答の1つ。ありがとうございました。
Mitya

警告!!!DSTタイムゾーンでの現地時間の使用または現地時間からの変換は、夏時間の終了時に、毎年1時間、1時間の誤差が生じます。これは、パラメータの1つが `@@ session.time_zone。UNIX_TIMESTAMP(NOW());であるCONVERT_TZ()場合のすべての使用に影響します。UTC日時をUNIXタイムスタンプに確実に変換するには、基本的にセッションtime_zoneを最初に設定する必要があります。
Doin '25年

1
@Flimm完全に正しい、私はそれを少し前に修正するのを忘れていました。
Timo Huovinen、

3

これは実際の例です:

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

2

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

このチュートリアルを読む:PHPとMySQLのタイムゾーンを同期する方法


それは基本的に2行のコードです:date_default_timezone_set("America/Los_Angeles");そしてmysql_query("SET time_zone='" . date('P', time()) . "'");非常にエレガントに動作しました!
Noumenon 2015年

3
@Noumenon気をつけて!それがまさに私がやっていたことであり、私の時間のいくつかは今1時間ずれているので、私は今朝頭を掻いています。名前付きタイムゾーンを使用すると、DSTが関係している場合により正確になると私は推測します。America / New_Yorkを使用する場合、MySQLはDSTを認識し、日付を適切に保存します。ここのように-04:00に設定しただけでは、DST計算は考慮されません。
nathanb 2015年

1
mysqlがDSTを正しく認識しているか、DSTルールが定期的に更新され、関連するmysqlテーブルも更新する必要があるかどうかを確認してください(上記の私の回答の最後を参照)
Timo Huovinen

1

長所と短所はほとんど同じです。これが必要かどうかによって異なります。

MySQLのタイムゾーンがシステムの時刻(PHPなど)と異なる場合は、時刻を比較したり、ユーザーに出力したりするときに多少の調整が必要になるので注意してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.