Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

PHP, MySQL dan Zona Waktu

Jawaban ini telah diperbarui untuk mengakomodasi hadiah. Jawaban asli yang belum diedit ada di bawah garis.

Hampir semua pertanyaan yang ditambahkan oleh pemilik bounty berhubungan dengan bagaimana MySQL dan PHP datetimes harus berinteraksi, dalam konteks zona waktu.

MySQL masih memiliki menyedihkan dukungan zona waktu , yang berarti bahwa kecerdasan harus berada di sisi PHP.

  • Setel zona waktu koneksi MySQL Anda ke UTC seperti yang didokumentasikan dalam tautan di atas. Ini akan menyebabkan semua waktu ditangani oleh MySQL, termasuk NOW() , untuk ditangani dengan bijaksana.
  • Selalu gunakan DATETIME , jangan pernah gunakan TIMESTAMP kecuali jika Anda sangat membutuhkan perilaku khusus dalam TIMESTAMP . Ini tidak terlalu menyakitkan dari sebelumnya.
    • Tidak apa-apa untuk menyimpan waktu zaman Unix sebagai bilangan bulat jika Anda memiliki untuk, seperti untuk tujuan warisan. Zamannya adalah UTC.
    • Format waktu tanggal pilihan MySQL dibuat menggunakan string format tanggal PHP Y-m-d H:i:s
  • Konversikan semua PHP datetime ke UTC saat menyimpannya di MySQL, yang merupakan hal sepele seperti yang diuraikan di bawah ini
  • Waktu yang dikembalikan dari MySQL dapat diserahkan dengan aman ke konstruktor PHP DateTime. Pastikan untuk melewati zona waktu UTC juga!
  • Konversi DateTime PHP ke zona waktu lokal pengguna on echo , tidak lebih cepat. Untungnya, perbandingan DateTime dan matematika terhadap DateTimes lainnya akan memperhitungkan zona waktu masing-masing.
  • Anda masih mengikuti keinginan database DST yang disediakan bersama PHP. Tetap perbarui patch PHP dan OS Anda! Pertahankan MySQL dalam kondisi UTC yang menyenangkan untuk menghilangkan satu gangguan DST potensial.

Alamat itu sebagian besar dari poin.

Hal terakhir adalah doozy:

  • Apa yang harus dilakukan seseorang jika mereka telah memasukkan data sebelumnya (mis. menggunakan NOW() ) tanpa mengkhawatirkan zona waktu untuk memastikan semuanya tetap konsisten?

Ini adalah gangguan nyata. Salah satu jawaban lain menunjukkan MySQL CONVERT_TZ , meskipun secara pribadi saya melakukannya dengan melompat antara zona waktu asli server dan UTC selama pemilihan dan pembaruan, karena saya hardcore seperti itu.

aplikasi juga harus dapat menyetel/memilih DST yang sesuai untuk setiap pengguna.

Anda tidak perlu dan tidak boleh lakukan ini di era modern.

Versi PHP modern memiliki DateTimeZone class, yang mencakup kemampuan untuk mendaftar zona waktu bernama . Zona waktu yang dinamai memungkinkan pengguna untuk memilih lokasi mereka yang sebenarnya, dan membuat sistem secara otomatis menentukan aturan DST mereka berdasarkan lokasi itu.

Anda dapat menggabungkan DateTimeZone dengan DateTime untuk beberapa fungsi sederhana namun kuat. Anda cukup menyimpan dan menggunakan semua stempel waktu Anda di UTC secara default , dan mengonversinya ke zona waktu pengguna yang ditampilkan.

// UTC default
    date_default_timezone_set('UTC');
// Note the lack of time zone specified with this timestamp.
    $nowish = new DateTime('2011-04-23 21:44:00');
    echo $nowish->format('Y-m-d H:i:s'); // 2011-04-23 21:44:00
// Let's pretend we're on the US west coast.  
// This will be PDT right now, UTC-7
    $la = new DateTimeZone('America/Los_Angeles');
// Update the DateTime's timezone...
    $nowish->setTimeZone($la);
// and show the result
    echo $nowish->format('Y-m-d H:i:s'); // 2011-04-23 14:44:00

Dengan menggunakan teknik ini, sistem akan secara otomatis pilih pengaturan DST yang benar untuk pengguna, tanpa bertanya kepada pengguna apakah mereka sedang menggunakan DST atau tidak.

Anda dapat menggunakan metode serupa untuk merender menu pilih. Anda dapat terus menetapkan kembali zona waktu untuk objek DateTime tunggal. Misalnya, kode ini akan mencantumkan zona dan waktunya saat ini, pada saat ini:

$dt = new DateTime('now', new DateTimeZone('UTC')); 
foreach(DateTimeZone::listIdentifiers() as $tz) {
    $dt->setTimeZone(new DateTimeZone($tz));
    echo $tz, ': ', $dt->format('Y-m-d H:i:s'), "\n";
}

Anda dapat sangat menyederhanakan proses pemilihan dengan menggunakan beberapa keajaiban sisi klien. Javascript memiliki berbintik-bintik tetapi berfungsi Kelas tanggal, dengan metode standar untuk mendapatkan offset UTC dalam hitungan menit . Anda dapat menggunakan ini untuk membantu mempersempit daftar kemungkinan zona waktu, dengan asumsi buta bahwa jam pengguna benar.

Mari kita bandingkan metode ini dengan melakukannya sendiri. Anda harus benar-benar melakukan matematika tanggal setiap saat Anda memanipulasi datetime, selain mendorong pilihan pada pengguna yang tidak akan mereka pedulikan. Ini bukan hanya kurang optimal, ini gila kelelawar-guano. Memaksa pengguna untuk memberi tanda saat mereka menginginkan dukungan DST menimbulkan masalah dan kebingungan.

Selanjutnya, jika Anda ingin menggunakan kerangka kerja DateTime dan DateTimeZone PHP modern untuk ini, Anda perlu gunakan Etc/GMT... string zona waktu bukannya zona waktu bernama. Nama zona ini dapat dihapus dari versi PHP mendatang, jadi tidak bijaksana untuk melakukannya. Saya mengatakan semua ini dari pengalaman.

tl;dr :Gunakan perangkat modern, hindari kengerian matematika tanggal. Berikan daftar bernama . kepada pengguna zona waktu. Simpan tanggal Anda dalam UTC , yang tidak akan terpengaruh oleh DST dengan cara apa pun. Konversi waktu tanggal ke zona waktu bernama yang dipilih pengguna di layar , tidak lebih awal.

Seperti yang diminta, berikut adalah pengulangan zona waktu yang tersedia yang menampilkan offset GMT-nya dalam hitungan menit. Saya memilih menit di sini untuk menunjukkan fakta yang tidak menguntungkan:tidak semua offset dalam satu jam penuh! Beberapa benar-benar beralih setengah jam ke depan selama DST, bukan satu jam penuh. Offset yang dihasilkan dalam hitungan menit seharusnya cocok dengan Date.getTimezoneOffset Javascript .

$utc = new DateTimeZone('UTC');
$dt = new DateTime('now', $utc); 
foreach(DateTimeZone::listIdentifiers() as $tz) {
    $local = new DateTimeZone($tz);
    $dt->setTimeZone($local);
    $offset = $local->getOffset($dt); // Yeah, really.
    echo $tz, ': ', 
         $dt->format('Y-m-d H:i:s'),
         ', offset = ',
         ($offset / 60),
         " minutes\n";
}


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Koneksi ke Db mati setelah>4<24 di spring-boot jpa hibernate

  2. Kode Kesalahan:1406. Data terlalu panjang untuk kolom - MySQL

  3. Tidak dapat terhubung ke server MySQL lokal melalui socket '/tmp/mysql.sock

  4. Pilih N baris terakhir dari MySQL

  5. MySQL Pilih semua kolom dari satu tabel dan beberapa dari tabel lain