MySQL'in saat dilimi UTC olarak ayarlanmış mı?


149

Https://serverfault.com/questions/191331/should-servers-have-their-timezone-set-to-gmt-utc soru takip

MySQL saat dilimi UTC'ye mi ayarlanmalı yoksa sunucu veya PHP'nin ayarlandığı saat dilimi olarak mı ayarlanmalıdır? (UTC değilse)

Artıları ve eksileri nelerdir?


stackoverflow.com/a/1650406/175071 UTC kullanarak için hisse iyi nedenler
Timo Huovinen

UTC bir saat dilimi değildir. UTC standart, GMT saat dilimi. zachholman.com/talk/utc-is-enough-for-everyone-right
agoldev

UTC kullanmak için başka bir harika neden dba.stackexchange.com/questions/161416/…
Timo Huovinen

Yanıtlar:


533

Geçerli saat dilimi için doğru zaman ayarladığınız, depoladığınız tarih saat sütunlarının saat dilimini bildiğiniz ve yaz saati uygulamasıyla ilgili sorunların farkında olduğunuz sürece, sunucuda saat diliminin ne olduğu önemli değildir.

Öte yandan, birlikte çalıştığınız sunucuların zaman dilimlerini kontrol ediyorsanız, her şey dahili olarak UTC'ye ayarlanmış olabilir ve zaman dilimleri ve DST hakkında asla endişelenmeyebilirsiniz.

İşte kendim ve diğerleri için kişinin sunucu için hangi saat dilimini seçeceğini ve tarih ve saati nasıl saklayacağını etkileyebilecek zaman çizelgeleri ile bir hile sayfası olarak nasıl çalışacağına dair topladığım bazı notlar.

MySQL Saat Dilimi Hileleri

Notlar:

  1. Saat dilimini değiştirmek, depolanan tarih saatini veya zaman damgasını değiştirmez , ancak zaman damgası sütunlarından farklı bir tarih saati seçer
  2. Uyarı! UTC'nin artık saniye sayısı var, bunlar '2012-06-30 23:59:60' gibi görünüyor ve dünya dönmesinin yavaşlaması nedeniyle 6 ay önceden bildirimde bulunarak rastgele eklenebilir.
  3. GMT saniyeler karıştırır, bu yüzden UTC icat edildi.

  4. Uyarı! Farklı bölgesel saat dilimleri, gün ışığından yararlanma saati nedeniyle aynı tarih saatini üretebilir

  5. Zaman damgası sütunu, bir sınırlama nedeniyle yalnızca 1970-01-01 00:00:01 - 2038-01-19 03:14:07 UTC tarihlerini destekler .
  6. Dahili olarak bir MySQL zaman damgası sütunu UTC olarak depolanır ancak bir tarih seçildiğinde MySQL bunu otomatik olarak geçerli oturum saat dilimine dönüştürür.

    Bir tarihi bir zaman damgasında saklarken, MySQL, tarihin geçerli oturum saat diliminde olduğunu varsayar ve saklama için UTC'ye dönüştürür.

  7. MySQL, kısmi tarihleri ​​datetime sütunlarında saklayabilir, bunlar "2013-00-00 04:00:00" gibi görünür
  8. MySQL, bir datetime sütununu NULL olarak ayarlarsanız, özellikle sütunu oluştururken null değerine izin verecek şekilde ayarlamadıysanız "0000-00-00 00:00:00" değerini depolar.
  9. Oku bunu

UTC biçiminde bir zaman damgası sütunu seçmek için

Geçerli MySQL oturumunun hangi saat diliminde olursa olsun:

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

Sunucu veya global veya geçerli oturum saat dilimini UTC olarak ayarlayabilir ve ardından zaman damgasını şu şekilde seçebilirsiniz:

SELECT `timestamp_field` FROM `table_name`

UTC'de geçerli tarih saatini seçmek için:

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

Örnek sonuç: 2015-03-24 17:02:41

Oturum saat diliminde geçerli tarih saatini seçmek için

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

Sunucu başlatıldığında ayarlanan saat dilimini seçmek için

SELECT @@system_time_zone;

Örneğin, Moskova zamanı için "MSK" veya "+04: 00" değerini döndürür, sayısal bir ofsete ayarlanırsa Yaz Saati uygulamasını ayarlamayacağı bir MySQL hatası vardır (ya da olmuştur)

Geçerli saat dilimini almak için

SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP);

Saat diliminiz +2: 00 ise 02:00:00 döndürecektir.

Geçerli UNIX zaman damgasını almak için (saniye cinsinden):

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

Zaman damgası sütununu UNIX zaman damgası olarak almak için

SELECT UNIX_TIMESTAMP(`timestamp`) FROM `table_name`

UTC tarih / saat sütununu UNIX zaman damgası olarak almak için

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

Olumlu bir UNIX zaman damgası tamsayısından geçerli saat dilimi tarih saatini alma

SELECT FROM_UNIXTIME(`unix_timestamp_int`) FROM `table_name`

UNIX zaman damgasından UTC tarih saati alma

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

Negatif UNIX zaman damgası tamsayısından geçerli saat dilimi tarih saatini alma

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

MySQL'de saat diliminin ayarlanabileceği 3 yer vardır:

Not: Bir saat dilimi 2 biçimde ayarlanabilir:

  1. UTC'den bir uzaklık: '+00: 00', '+10: 00' veya '-6: 00'
  2. adlandırılmış bir saat dilimi olarak: 'Avrupa / Helsinki', 'ABD / Doğu' veya 'MET'

Adlandırılmış saat dilimleri yalnızca mysql veritabanındaki saat dilimi bilgi tabloları oluşturulmuş ve doldurulmuşsa kullanılabilir.

"my.cnf" dosyasında

default_time_zone='+00:00'

veya

timezone='UTC'

@@ global.time_zone değişkeni

Hangi değere ayarlandıklarını görmek için

SELECT @@global.time_zone;

Bunun için bir değer ayarlamak için birini kullanın:

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

@@ session.time_zone değişkeni

SELECT @@session.time_zone;

Ayarlamak için birini kullanın:

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

hem "@@ global.time_zone değişkeni" hem de "@@ session.time_zone değişkeni", "SİSTEM" i döndürebilir, bu da "my.cnf" içinde ayarlanan saat dilimini kullandıkları anlamına gelir.

Saat dilimi adlarının çalışması için (varsayılan saat dilimi için bile) saat dilimi bilgi tablolarınızın doldurulması gerekir: http://dev.mysql.com/doc/refman/5.1/en/time-zone-support. html

Not: NULL döndüreceği için bunu yapamazsınız:

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

MySQL saat dilimi tablolarını ayarlama

İçin CONVERT_TZişe, sen saat dilimi tabloları doldurulması gerekmektedir

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

Boşlarsa, bu komutu çalıştırarak doldurun

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

Bu komut size " satır 1'deki 'kısaltma' sütunu için çok uzun veri " hatasını veriyorsa, bunun nedeni saat dilimi kısaltmasının sonuna bir NULL karakterin eklenmesi olabilir.

düzeltme bunu çalıştırmak için

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

(sunucularınızın ilk kurallarının güncel olduğundan emin olun zdump -v Europe/Moscow | grep 2011 https://chrisjean.com/updating-daylight-saving-time-on-linux/ )

Her saat dilimi için tam DST (Yaz Saati Uygulaması) geçiş geçmişine bakın

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 yukarıdaki tablolardaki kurallara ve kullandığınız tarihe göre gerekli DST değişikliklerini de uygular.

Not: Dokümanlara
göre , time_zone için ayarladığınız değer değişmez, örneğin "+01: 00" olarak ayarlarsanız, time_zone DST'yi takip etmeyen UTC'den ofset olarak ayarlanır, bu nedenle tüm yıl boyunca aynı kalacaktır.

Yaz saati uygulaması sırasında yalnızca belirtilen saat dilimleri değişecektir.

Gibi kısaltmalar CETher zaman kış ve CESTyaz saati, +01: 00 her zamanUTC zaman + 1 saat olacak ve her ikisi de DST ile değişmeyecek.

Saat systemdilimi, mysql'nin kurulu olduğu ana makinenin saat dilimi olacaktır (mysql bunu belirleyemezse)

DST ile çalışma hakkında daha fazla bilgiyi buradan edinebilirsiniz.

ilgili sorular:

Kaynaklar:


Sütun tipimi zaman damgası olarak ayarladıysam. Ve benim time_zone +12: 00, ve ben utc tabanlı bir tarih / saat kullanarak bir sütun güncellemek istiyorum, güncelleme deyimine saat dilimi dahil etmek için herhangi bir yolu var mı, ya da convert_tz kullanmak gerekir. Örneğin. güncelleme tableseti modified= '2016-07-07 08:10 +00: 00'
bumperbox

2
@bumperbox mysql her zaman zaman damgası sütununu verdiğiniz tarihin mysql sunucusuyla aynı saat diliminde olduğunu varsayar, bu nedenle tarihinizi güncelleme için +12: 00 saat diliminizden mysql sunucusu saat diliminize dönüştürmeniz gerekir. Bu yüzden mysql sunucusunda UTC kullanmak ve herhangi bir tarih saklamak önce UTC UTC dönüştürmek.
Timo Huovinen

5
SO kullanarak yıllar içinde karşılaştığım en iyi, en bilgilendirici cevaplardan biri. Teşekkür ederim.
Mitya

UYARI!!! DST saat diliminde yerel saatin herhangi bir şekilde kullanılması veya dönüştürülmesi, gün ışığından yararlanma sonunda her yıl bir saat boyunca yanlış olacaktır. Bu , parametrelerden birinin @ @ session.time_zone UNIX_TIMESTAMP(NOW());olduğu tüm kullanımlarınızı da etkiler CONVERT_TZ(). UTC tarihlerini UNIX zaman damgalarına güvenilir bir şekilde dönüştürmek için, önce oturumu time_zone olarak ayarlamanız gerekir.
Doin

1
@Flimm tamamen doğru, bunu bir süre önce düzeltmeyi unuttum.
Timo Huovinen

3

Bu çalışan bir örnektir:

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

2

PHP ve MySQL'in kendi varsayılan saat dilimi yapılandırmaları vardır. Veri tabanınız ve web uygulamanız arasında zamanı senkronize etmelisiniz, aksi takdirde bazı sorunları çalıştırabilirsiniz.

Bu öğreticiyi okuyun: PHP ve MySQL Zaman Dilimlerinizi Eşitleme


Temelde iki satır kod: date_default_timezone_set("America/Los_Angeles");ve mysql_query("SET time_zone='" . date('P', time()) . "'");çok zarif çalıştı!
Noumenon

3
@Noumenon Buna dikkat et! Bu sabah başımı kaşıyorum, çünkü tam olarak bunu yapıyordum ve bazı zamanlarım bir saat kadar kapalı. Şüphelendiğim, DST dahil olduğunda adlandırılmış bir saat dilimi kullanmanın daha doğru olmasıdır. America / New_York kullanırsanız, MySQL DST hakkında bilgi sahibi olur ve tarihleri ​​uygun şekilde saklar. Burada olduğu gibi -04: 00 olarak ayarlarsanız, DST hesaplaması dikkate alınmaz.
nathanb

1
DST doğru DST kuralları düzenli olarak güncellenen olsun ve ilgili MySQL tabloları da güncellenmesi (cevabım altındaki yukarıya bakınız) ihtiyaç hakkında MySQL biliyorsa yapmak kontrol
Timo Huovinen

1

Artıları ve eksileri hemen hemen aynıdır.Bu bunu isteyip istemediğinize bağlıdır.

Dikkatli olun, eğer MySQL saat dilimi sistem saatinizden (örneğin PHP) farklıysa, saati veya yazdırmayı kullanıcıyla karşılaştırmak bazı müdahaleleri içerir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.