MySQL datetime alanları ve gün ışığından tasarruf zamanı -

5 Cevap php

Ben Amerika / New York dilimini kullanıyorum. Sonbahar biz bir saat "düşmek" - etkili 02:00 az bir saat "kazanıyor". Geçiş noktada şu olur:

it's 01:59:00 -04:00
then 1 minute later it becomes:
01:00:00 -05:00

Eğer sadece "01:30" derseniz bu nedenle 01:30 etrafında rulo ilk kez ya da ikinci bahsediyorsan olup olmadığı gibi muğlak. Ben bir MySQL veritabanı zamanlama verileri kaydetmek çalışıyorum ve düzgün bir defa kaydedebilirsiniz nasıl belirleyemiyor.

Here's the problem:
"2009-11-01 00:30:00" is stored internally as 2009-11-01 00:30:00 -04:00
"2009-11-01 01:30:00" is stored internally as 2009-11-01 01:30:00 -05:00

Bu ince ve oldukça bekleniyor. Ama nasıl 01:30:00 şey kaydederim -04:00? documentation Ben ofset usulüne göz ardı edilmiş belirtirken denedim zaman, buna göre, ofset belirterek ve herhangi bir destek görünmüyor.

Ben düşündüm sadece çözümler yaz saati kullanın ve (ben bunun için PHP kullanıyorum) script'lerime gerekli dönüşümleri yaparak değil bir timezone sunucu ayarı içerir. Gerekli olması gerektiği gibi ama bu görünmüyor.

Herhangi bir öneriniz için çok teşekkürler.

5 Cevap

MySQL tarih türleri, açıkçası, kırık ve sistem UTC veya GMT-5 gibi sabit bir ofset zaman dilimi, ayarlanmadığı sürece doğru all kez saklayamazsınız. (Ben MySQL 5.0.45 kullanıyorum)

Bunun nedeni, you can't store any time during the hour before Daylight Saving Time ends. Olursa olsun anahtarından sonra saat içinde iseniz gibi giriş tarihleri, her tarih işlevi, bu kez nasıl tedavi edeceği.

Benim sistemin timezone America/New_York. En 1257051600 (Sun, 1 Kasım 2009 06:00:00 +0100) depolamak deneyelim.

İşte tescilli ARALIK sözdizimini kullanarak bulunuyor:

SELECT UNIX_TIMESTAMP('2009-11-01 00:00:00' + INTERVAL 3599 SECOND); # 1257051599
SELECT UNIX_TIMESTAMP('2009-11-01 00:00:00' + INTERVAL 3600 SECOND); # 1257055200

SELECT UNIX_TIMESTAMP('2009-11-01 01:00:00' - INTERVAL 1 SECOND); # 1257051599
SELECT UNIX_TIMESTAMP('2009-11-01 01:00:00' - INTERVAL 0 SECOND); # 1257055200

Hatta FROM_UNIXTIME() doğru zaman dönmeyecek.

SELECT UNIX_TIMESTAMP(FROM_UNIXTIME(1257051599)); # 1257051599
SELECT UNIX_TIMESTAMP(FROM_UNIXTIME(1257051600)); # 1257055200

İşin tuhafı, DATETIME will hala saklamak ve (string şeklinde sadece!) Return kez "kayıp" bir saat içinde DST başlar (örneğin, 2009-03-08 02:59:59). Ama herhangi bir MySQL fonksiyonu bu tarihleri ​​kullanarak risklidir:

SELECT UNIX_TIMESTAMP('2009-03-08 01:59:59'); # 1236495599
SELECT UNIX_TIMESTAMP('2009-03-08 02:00:00'); # 1236495600
# ...
SELECT UNIX_TIMESTAMP('2009-03-08 02:59:59'); # 1236495600
SELECT UNIX_TIMESTAMP('2009-03-08 03:00:00'); # 1236495600

Paket: Eğer yıl every zaman saklamak ve almak gerekiyorsa, birkaç istenmeyen seçenek var:

  1. Set sistem GMT timezone + sabit bazı ofset. Örneğin UTC
  2. Mağaza (Aaron keşfettiği gibi, TIMESTAMP bile güvenilir değildir) IntS gibi Tarihleri

  3. DATETIME tipi bazı sabit ofset dilimini vardır davran. Örneğin Eğer America/New_York, GMT-5 için tarih dönüştürmek iseniz outside of MySQL, daha sonra bir DATETIME (: Harun'un cevabı görmek bu önemli olduğu ortaya çıkıyor) olarak saklayın. Bazı sizin değerler sistemi diliminin varsayıyorum çünkü o zaman, MySQL tarih / saati fonksiyonlarını kullanarak çok dikkat etmelidir, diğerleri (özellikle zaman aritmetik fonksiyonlar) "agnostik timezone" (zamanlar UTC sanki davranabilir) vardır.

Harun ve ben oto üreten DAMGASI sütunlar da kırık olduğunu sanıyorum. Her iki 2009-11-01 01:30 -0400 ve 2009-11-01 01:30 -0500 belirsiz 2009-11-01 01:30 şeklinde kaydedilir.

Ben benim amaçlar için çözdüm. (Üzgünüm, bu notlar ayrıntılı, onlar başka bir şey olarak benim gelecekteki sevk kadar konum) öğrendiklerimi özetlemek olacak.

Ben önceki yorum, DATETIME ve TIMESTAMP alanlarından birinde söylediklerini aksine do farklı davranır. Biçim ve UTC zaman için geçerli saatle onu dönüştürmek DAMGASI alanlar (docs göstermek gibi) ": mm ss YYYY-AA-GG SS" bunları göndermek ne olursa olsun almak. Eğer veri almak her ters şeffaf olur. DATETIME alanları bu dönüşümü yapmazlar. Onlar bunları göndermek ne olursa olsun almak ve sadece doğrudan saklayın.

Neither the DATETIME nor the TIMESTAMP field types can accurately store data in a timezone that observes DST. Eğer "2009-11-01 01:30:00" saklarsanız alanları istediğini 01:30 hangi sürümünü ayırmak için bir yol var - -04:00 veya -05:00 sürümü.

Tamam, bu yüzden (örneğin UTC gibi) olmayan bir DST zaman dilimi bizim veri depolamak gerekir. TIMESTAMP alanlar ben açıklayacağım nedenlerle doğru bu verileri işlemek edemiyoruz: Sisteminiz bir DST zaman dilimine ayarlı ise o zaman ne TIMESTAMP koymak geri çıkmak ne olmayabilir. Bunu zaten UTC dönüştürülür ettik veri göndermek bile, yine yerel saat diliminde veri bulunuyor üstlenecek ve UTC henüz başka bir dönüşüm yapacağız. Yerel saat dilimi DST gözlemlediği zaman bu DAMGASI zorlanan yerel-to-UTC-back-to-yerel gidiş dönüş (2 farklı olası kere "2009-11-01 01:30:00" haritalar beri) kayıplı.

DateTime ile istediğiniz herhangi bir zaman dilimi içinde veri depolamak ve sen (siz DAMGASI alanların size yutturmak kayıplı gidiş dönüş dönüşümleri zorla alamadım) ne gönderirseniz geri alırsınız emin olabilirsiniz. Yani çözüm DATETIME alanını kullanın ve before saving to the field (I UTC muhtemelen en iyi seçenek olduğunu düşünüyorum) sen onu kaydetmek istediğiniz ne olursa olsun olmayan DST bölge içine sistem zaman dilimi dönüştürmektir. Bu açıkça 01:30 "2009-11-01 01:30:00 -04:00" arasında UTC eşdeğer tasarruf ya da "" 2009-11-01 böylece kendi betik dili haline dönüştürme mantığı oluşturmanıza olanak verir: 00 -05:00 ".

Unutulmaması gereken bir diğer önemli şey, bir DST TZ tarihleri ​​saklıyorsanız MySQL tarih / saati matematik fonksiyonları DST sınırları etrafında düzgün çalışmaz kalmamasıdır. Yani UTC kurtarmak için tüm neden daha.

Özetle ben şimdi bunu:

When retrieving the data from the database:

Açıkça doğru bir Unix zaman damgası almak için MySQL dışında UTC olarak veritabanından verileri yorumlamak. Bunun için PHP'nin strtotime () işlevi veya DateTime sınıfını kullanın. CONVERT_TZ çıkışı, sadece bir ': mm: YYYY-AA-GG ss ss' olacaktır, çünkü güvenilir MySQL'in CONVERT_TZ () veya UNIX_TIMESTAMP () işlevleri kullanılarak MySQL içinde yapılamaz belirsizlik sorunlardan muzdarip değer ve UNIX_TIMESTAMP () varsayar onun giriş sistemi timezone değil, veri ASLINDA (UTC) depolanan dilimi bulunmaktadır.

When storing the data to the database:

MySQL dışında arzu kesin UTC zaman tarih dönüştürün. Örneğin: PHP'nin DateTime sınıfının ile UTC dönüştürmek, sonra belirgin "2009-11-01 01:30:00 EEST" dan "2009-11-01 01:30:00 EST" belirlemek ve doğru UTC zamandan tasarruf edebilirsiniz Lütfen DATETIME alana.

Vay. Teşekkürler herkesin girdi ve yardım için çok. Umarım bu başkası yolda bazı baş ağrısı kaydeder.

BTW, MySQL 5.0.22 ve 5.0.27 bu görüyorum

Bağladığınızda UTC oturum dilimini ayarlayın: Ben micahwittman en link bu MySQL sınırlamalara en iyi pratik çözüm olduğunu düşünüyorum:

SET SESSION time_zone = '+0:00'

Sonra sadece bunu Unix zaman damgalarını göndermek ve her şeyi ince olmalıdır.

But how do I save anything to 01:30:00 -04:00?

Sen gibi UTC dönüştürebilirsiniz:

SELECT CONVERT_TZ('2009-11-29 01:30:00','-04:00','+00:00');


Even better, save the dates as a TIMESTAMP field. That's always stored in UTC, and UTC doesn't know about summer/winter time.

Sen kullanarak localtime UTC dönüştürebilirsiniz CONVERT_TZ:

SELECT CONVERT_TZ(UTC_TIMESTAMP(),'+00:00','SYSTEM');

'+00:00' UTC, timezone gelen ve 'SYSTEM' MySQL çalışan işletim yerel timezone olduğu.

Bir datawarehouse değişti kayıtları ve ETL izlemek için: Bu konu biz On UPDATE CURRENT_TIMESTAMP (recordTimestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP yani) ile TIMESTAMP sütunları kullanabilirsiniz beri bana ucube yaptı.

Durumda birisi şaşkınlıkla, bu durumda, TIMESTAMP doğru davranmaya ve Unix zaman damgası için TIMESTAMP dönüştürerek benzer iki tarih arasında ayırt edebilirsiniz:

select TestFact.*, UNIX_TIMESTAMP(recordTimestamp) from TestFact;

id  recordTimestamp         UNIX_TIMESTAMP(recordTimestamp)
1   2012-11-04 01:00:10.0   1352005210
2   2012-11-04 01:00:10.0   1352008810