PHP & mySQL: Bug Tahun 2038: Apa itu? Bagaimana cara mengatasinya?

116

Saya berpikir untuk menggunakan TIMESTAMP untuk menyimpan tanggal + waktu, tetapi saya membaca bahwa ada batasan tahun 2038 di situ. Alih-alih menanyakan pertanyaan saya secara massal, saya lebih suka memecahnya menjadi bagian-bagian kecil agar mudah dipahami oleh pengguna pemula juga. Jadi pertanyaan saya:

  1. Apa sebenarnya masalah Tahun 2038?
  2. Mengapa itu terjadi dan apa yang terjadi?
  3. Bagaimana kita mengatasinya?
  4. Apakah ada alternatif lain yang mungkin untuk digunakan, yang tidak menimbulkan masalah serupa?
  5. Apa yang dapat kita lakukan untuk aplikasi yang sudah ada yang menggunakan TIMESTAMP, untuk menghindari masalah yang disebut, ketika itu benar-benar terjadi?

Terima kasih sebelumnya.

Devner
sumber
1
Itu masih 28 tahun lagi. Apakah Anda masih menggunakan teknologi terkait komputer dari tahun 1982? Tidak sepertinya. Jadi jangan khawatir, karena pada tahun 2038 kemungkinan tidak akan menjadi masalah lagi.
Gordon
24
Gordon, saya membuat aplikasi yang melakukan peramalan. Saya menabung berapa banyak uang yang saya miliki setiap bulan, dan kemudian dapat memperkirakan kapan saya akan menjadi jutawan. Dalam kasus saya, 28 tahun tidaklah terlalu banyak, dan saya yakin saya bukan satu-satunya yang mengalami masalah ini sekarang (saya menyelesaikannya dengan menggunakan angka 64-bit untuk mewakili stempel waktu).
Emil Vikström
2
@Emil Dengan menggunakan integer 64bit sekarang , Anda telah menemukan sendiri solusi mudah untuk masalah konkret. Tidak berlaku untuk (atau dibutuhkan oleh) semua orang, tetapi bekerja untuk kasus penggunaan Anda. Intinya adalah, jika OP tidak memiliki masalah konkret, seperti peramalan, maka ini mungkin topik yang menarik, tetapi tidak ada yang perlu dia khawatirkan, karena menyelesaikan ini pada tingkat umum bukanlah masalah PHP (mind the tag). Hanya 2c saya.
Gordon
1
Pada tahun 2038, mengurai string "YYYY-MM-DD HH: MM: SS: mmmm ..." akan menjadi operasi termurah yang dapat Anda impikan. Pada tahun 2038, 32 Bit akan menjadi usang. Saya meragukan stempel waktu Unix yang kami tahu akan ada saat itu, dan jika ya, sistem 256 Bit kami akan menangani tanggal yang melampaui usia di mana sistem 4096 bit diberikan dalam acara makan bahagia.
Super Cat
8
Gordon, 9 tahun kemudian sekarang. TIMESTAMPS masih digunakan. Kami masih menggunakan teknologi dari 28 tahun lalu. Ini disebut world wide web.
sfscs

Jawaban:

149

Saya telah menandai ini sebagai wiki komunitas jadi silakan mengeditnya kapan saja.

Apa sebenarnya masalah Tahun 2038?

"Masalah tahun 2038 (juga dikenal sebagai Unix Millennium Bug, Y2K38 dengan analogi masalah Y2K) dapat menyebabkan beberapa perangkat lunak komputer gagal sebelum atau di tahun 2038. Masalah tersebut mempengaruhi semua perangkat lunak dan sistem yang menyimpan waktu sistem sebagai 32 yang ditandatangani -bit integer, dan tafsirkan angka ini sebagai jumlah detik sejak 00:00:00 UTC pada 1 Januari 1970. "


Mengapa itu terjadi dan apa yang terjadi?

Waktu setelah 03:14:07 UTC pada hari Selasa, 19 Januari 2038 akan 'membungkus' dan disimpan secara internal sebagai angka negatif, yang akan ditafsirkan oleh sistem ini sebagai waktu pada 13 Desember 1901 daripada pada 2038. Hal ini disebabkan oleh fakta bahwa jumlah detik sejak masa UNIX (1 Januari 1970 00:00:00 GMT) akan melebihi nilai maksimum komputer untuk bilangan bulat bertanda 32-bit.


Bagaimana kita mengatasinya?

  • Gunakan tipe data yang panjang (64 bit sudah cukup)
  • Untuk MySQL (atau MariaDB), jika Anda tidak memerlukan informasi waktu, pertimbangkan untuk menggunakan DATEjenis kolom. Jika Anda membutuhkan akurasi yang lebih tinggi, gunakan DATETIMEdaripada TIMESTAMP. Berhati-hatilah karena DATETIMEkolom tidak menyimpan informasi tentang zona waktu, jadi aplikasi Anda harus mengetahui zona waktu mana yang digunakan.
  • Solusi lain yang mungkin dijelaskan di Wikipedia
  • Tunggu hingga pengembang MySQL memperbaiki bug ini yang dilaporkan lebih dari satu dekade lalu.

Apakah ada alternatif lain yang mungkin untuk digunakan, yang tidak menimbulkan masalah serupa?

Cobalah sedapat mungkin untuk menggunakan tipe besar untuk menyimpan tanggal dalam database: 64-bit sudah cukup - tipe panjang yang panjang di GNU C dan POSIX / SuS, atau sprintf('%u'...)dalam PHP atau ekstensi BCmath.


Apa sajakah kasus penggunaan yang berpotensi merusak meskipun kami belum berada di tahun 2038?

Jadi MySQL DATETIME memiliki kisaran 1000-9999, tetapi TIMESTAMP hanya memiliki kisaran 1970-2038. Jika sistem Anda menyimpan tanggal lahir, tanggal mendatang (mis. Hipotek 30 tahun), atau serupa, Anda sudah akan mengalami bug ini. Sekali lagi, jangan gunakan TIMESTAMP jika ini akan menjadi masalah.


Apa yang dapat kita lakukan untuk aplikasi yang sudah ada yang menggunakan TIMESTAMP, untuk menghindari masalah yang disebut, ketika itu benar-benar terjadi?

Beberapa aplikasi PHP masih akan ada pada tahun 2038, meskipun sulit untuk meramalkan karena web bukanlah platform lama.

Berikut adalah proses untuk mengubah kolom tabel database untuk mengkonversi TIMESTAMPke DATETIME. Ini dimulai dengan membuat kolom sementara:

# rename the old TIMESTAMP field
ALTER TABLE `myTable` CHANGE `myTimestamp` `temp_myTimestamp` int(11) NOT NULL;

# create a new DATETIME column of the same name as your old column
ALTER TABLE `myTable` ADD `myTimestamp` DATETIME NOT NULL;

# update all rows by populating your new DATETIME field
UPDATE `myTable` SET `myTimestamp` = FROM_UNIXTIME(temp_myTimestamp);

# remove the temporary column
ALTER TABLE `myTable` DROP `temp_myTimestamp`

Sumber daya

Corey Ballou
sumber
2
Mengagumkan. Bagiku, jawabanmu adalah yang paling lengkap. Terimakasih banyak.
Devner
7
Di MySQL, jika versi mendatang mengubah jenis data penyimpanan yang mendasari TIMESTAMP menjadi 64-bit, maka tidak perlu mengubah kode Anda menjadi DATETIME, bukan? Saya hanya tidak berpikir mengecilkan hati siapa pun untuk menggunakan TIMESTAMP adalah hal yang benar untuk dilakukan karena tipe data itu memang ada tujuannya.
pixelfreak
1
Bidang BIGINT yang ditandatangani MySQL sepertinya akan berfungsi dengan baik untuk menyimpan cap waktu dan saya telah melakukan beberapa pengujian lokal pada MySQL 5.5 yang mengonfirmasi itu berfungsi. Jelas menggunakan ditandatangani akan lebih baik daripada unsigned karena Anda dapat mewakili tanggal di masa lalu juga. Ada alasan untuk tidak menggunakan BIGINT sebagai cap waktu?
zuallauz
Satu hal yang perlu diperhatikan, MySQL hanya memiliki pengaturan otomatis ke tanggal / waktu saat ini (CURRENT_TIMESTAMP) untuk bidang cap waktu. Mudah-mudahan, fungsi ini pada akhirnya akan ditransfer ke semua jenis tanggal.
Ray
5
Benar-benar tidak masuk akal bahwa MySQL (dan MariaDB) tidak menggunakan 64 bit integer untuk menyimpan cap waktu pada sistem 64 bit. Menggunakan DATETIME bukanlah solusi yang memadai karena kami tidak tahu tentang zona waktu. Ini telah dilaporkan pada tahun 2005 , tetapi masih belum ada perbaikan yang tersedia.
Mike
14

Saat menggunakan Stempel Waktu UNIX untuk menyimpan tanggal, Anda sebenarnya menggunakan bilangan bulat 32 bit, yang menghitung jumlah detik sejak 1970-01-01; lihat Waktu Unix

Angka 32 bit itu akan meluap pada tahun 2038. Itulah masalah tahun 2038.


Untuk mengatasi masalah itu, Anda tidak boleh menggunakan stempel waktu UNIX 32 bit untuk menyimpan tanggal Anda - yang berarti, saat menggunakan MySQL, Anda tidak boleh menggunakan TIMESTAMP, tetapi DATETIME(lihat 10.3.1. Jenis DATETIME, DATE, dan TIMESTAMP ):

The DATETIMEjenis digunakan ketika Anda membutuhkan nilai-nilai yang mengandung kedua tanggal dan informasi waktu. Rentang yang didukung adalah '1000-01-01 00:00:00'untuk '9999-12-31 23:59:59'.

The TIMESTAMPtipe data memiliki berbagai '1970-01-01 00:00:01'UTC ke '2038-01-19 03:14:07'UTC.


Hal (mungkin) terbaik yang dapat Anda lakukan untuk aplikasi Anda untuk menghindari / memperbaiki masalah tersebut adalah dengan tidak menggunakan TIMESTAMP, tetapi DATETIMEuntuk kolom yang harus berisi tanggal yang bukan antara tahun 1970 dan 2038.

Namun, ada satu catatan kecil: kemungkinan besar (secara statistik) aplikasi Anda akan ditulis ulang beberapa kali sebelum tahun 2038 ^^ Jadi mungkin, jika Anda tidak harus berurusan dengan tanggal di masa mendatang , Anda tidak perlu menangani masalah itu dengan versi aplikasi Anda saat ini ...

Pascal MARTIN
sumber
1
1 Untuk info. Upaya di sini adalah untuk mengadaptasi praktik terbaik sejak awal sehingga seseorang tidak perlu khawatir tentang masalah di kemudian hari. Jadi meskipun untuk saat ini 2038 mungkin tidak terdengar seperti masalah, saya hanya ingin mengikuti praktik terbaik dan mengikutinya untuk setiap & setiap aplikasi yang saya buat, langsung dari awal. Harapan itu masuk akal.
Devner
Ya, masuk akal, saya mengerti maksud Anda. Tapi "praktik terbaik" juga bisa berarti "apa yang menjawab kebutuhan" - Jika Anda tahu stempel waktu sudah cukup, tidak perlu menggunakan datetime (yang membutuhkan lebih banyak memori untuk disimpan, misalnya; dan itu bisa jadi masalah jika Anda memiliki jutaan catatan) ;; Saya memiliki beberapa aplikasi di mana saya menggunakan cap waktu untuk beberapa kolom (kolom yang berisi tanggal saat ini, misalnya), dan tanggal waktu untuk beberapa lainnya (kolom yang berisi tanggal lampau / masa depan, misalnya)
Pascal MARTIN
Saya melihat prosedur Anda juga masuk akal dan bekerja dengan baik terutama bila menyangkut ruang penyimpanan. Jika tidak apa-apa, boleh saya bertanya kepada Anda struktur dan panjang apa yang biasanya Anda gunakan untuk kolom TIMESTAMP di aplikasi Anda? Terima kasih.
Devner
Nah, ketika saya ingin menggunakan TIMESTAMP, itu untuk / karena data "tanggal / waktu" saya cocok antara tahun 1970 dan 2038 - dan, jadi, saya menggunakan tipe data MySQL TIMESTAMP.
Pascal MARTIN
Terimakasih atas infonya. Dari tanggapan Anda, saya mengerti bahwa cukup dengan mendeklarasikan kolom sebagai TIMESTAMP dan kami tidak perlu memberikan panjang apa pun untuk itu (tidak seperti dan int atau var, di mana kami memberikan panjangnya). Apakah saya benar?
Devner
7

Pencarian cepat di Google akan berhasil: Masalah tahun 2038

  1. Masalah tahun 2038 (juga dikenal sebagai Unix Millennium Bug, Y2K38 dengan analogi masalah Y2K) dapat menyebabkan beberapa perangkat lunak komputer gagal sebelum atau di tahun 2038
  2. Masalah ini memengaruhi semua perangkat lunak dan sistem yang menyimpan waktu sistem sebagai bilangan bulat 32-bit yang ditandatangani, dan menafsirkan angka ini sebagai jumlah detik sejak 00:00:00 UTC pada 1 Januari 1970. Waktu terbaru yang dapat direpresentasikan dengan cara ini adalah 03:14:07 UTC pada hari Selasa, 19 Januari 2038. Waktu di luar momen ini akan "membungkus" dan disimpan secara internal sebagai angka negatif, yang akan diinterpretasikan oleh sistem ini sebagai tanggal pada tahun 1901 bukan 2038
  3. Tidak ada perbaikan yang mudah untuk masalah ini untuk kombinasi CPU / OS yang ada, sistem file yang ada, atau format data biner yang ada
Rubens Farias
sumber
2

http://en.wikipedia.org/wiki/Year_2038_problem memiliki sebagian besar detail

Singkatnya:

1) + 2) Masalahnya adalah banyak sistem menyimpan info tanggal sebagai int 32-bit yang ditandatangani sama dengan jumlah detik sejak 1/1/1970. Tanggal terakhir yang dapat disimpan seperti ini adalah 03:14:07 UTC pada hari Selasa, 19 Januari 2038. Jika ini terjadi, int akan "membungkus" dan disimpan sebagai angka negatif yang akan diartikan sebagai tanggal pada tahun 1901. Apa sebenarnya yang akan terjadi kemudian, bervariasi dari sistem ke sistem tetapi cukup untuk mengatakan itu mungkin tidak akan baik untuk mereka!

Untuk sistem yang hanya menyimpan tanggal di masa lalu, maka saya rasa Anda tidak perlu khawatir untuk sementara waktu! Masalah utamanya adalah dengan sistem yang bekerja dengan tanggal di masa depan. Jika sistem Anda perlu bekerja dengan tanggal 28 tahun ke depan maka Anda harus mulai khawatir sekarang!

3) Gunakan salah satu format tanggal alternatif yang tersedia atau pindah ke sistem 64-bit dan gunakan int 64-bit. Atau untuk database menggunakan format cap waktu alternatif (misalnya untuk MySQL gunakan DATETIME)

4) Lihat 3!

5) Lihat 4 !!! ;)

Addsy
sumber
Poin 4 & 5 Anda mengingatkan saya pada 'Panggilan dengan Referensi'. Itu membuat saya tersenyum. Terima kasih & +1 untuk hal yang sama.
Devner
1

Saudaraku, jika Anda perlu menggunakan PHP untuk menampilkan cap waktu, ini adalah solusi PHP TERBAIK tanpa mengubah dari format UNIX_TIMESTAMP.

Gunakan fungsi custom_date (). Di dalamnya, gunakan DateTime. Inilah solusi DateTime .

Selama Anda memiliki UNSIGNED BIGINT (8) sebagai cap waktu Anda di database. Selama Anda memiliki PHP 5.2.0 ++

Dexter
sumber
-1

Karena saya tidak ingin mengupgrade apa pun, saya meminta backend (MSSQL) saya untuk melakukan pekerjaan ini alih-alih PHP!

$qry = "select DATEADD(month, 1, :date) next_date ";
$rs_tmp = $pdo->prepare($qry);
$rs_tmp->bindValue(":date", '2038/01/15');
$rs_tmp->execute();
$row_tmp = $rs_tmp->fetch(PDO::FETCH_ASSOC);

echo $row_tmp['next_date'];

Mungkin bukan cara yang efisien, tetapi berhasil.

Venkatesh GS Rao
sumber