171

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

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

長所と短所は何ですか?

4

5 に答える 5

611

現在のタイムゾーンに合わせて時刻が正しく設定されていて、保存する日時列のタイムゾーンを知っていて、夏時間の問題を認識している限り、サーバー上のタイムゾーンは問題ではないようです。

一方、使用するサーバーのタイムゾーンを制御できる場合は、内部ですべてを UTC に設定することができ、少なくとも内部時間の保存に関しては、タイムゾーンと DST について心配する必要はありません。

以下は、自分自身や他の人が自分のサーバーに選択するタイムゾーンと、日付と時刻を保存する方法に影響を与える可能性のあるチートシートの形式としてタイムゾーンを操作する方法について収集したメモです。

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

ノート:

  1. タイムゾーンを変更しても、保存されている datetime または timestamp は変更されませんが、timestamp 列から別の datetime が選択されます

  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. datetime カラムを NULL として設定すると、MySQL は「0000-00-00 00:00:00」を格納します。ただし、カラムを作成するときに特に null を許可するように設定しない限りは、.

  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

このコマンドで「data too long for column 'abbreviation' at row 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 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は、上記の表のルールと使用する日付に基づいて、必要な DST の変更も適用します。

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

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

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

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

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

伝説の Jon Skeet による UTC を使用しない場合: https://codeblog.jonskeet.uk/2019/03/27/storing-utc-is-not-a-silver-bullet/ (たとえば、将来予定されているイベント瞬間ではなく時間を表す)

関連する質問:

ソース:

于 2013-09-29T06:50:37.720 に答える
3

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

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

于 2013-09-26T09:21:59.647 に答える