Banyak di tahun 2020 menjadi korban fenomena aneh persepsi waktu, tetapi beberapa sistem manajemen basis data memanipulasi waktu lebih lama. Saya pertama kali memperhatikan ini ketika seorang teman saya di salah satu proyeknya ( Accord adalah bot Discord yang populer) menemukan pengecualian berikut dari konektor MySQL saat digunakan dengan EF Core:
MySqlException: Incorrect TIME value: '960:00:00.000000'
Tidak terlalu paham MySQL (karena saya lebih suka PostgreSQL karena alasan yang akan segera terlihat), saya berpikir sejenak bahwa jumlah jamnya salah. Masuk akal untuk mengasumsikan bahwa nilai TIME dibatasi hingga 24 jam, atau nilai yang mencakup beberapa hari memerlukan sintaks yang berbeda - misalnya,
40:00:00:00akan mewakili 40 hari. Namun kenyataannya ternyata jauh lebih rumit dan membingungkan.
Langkah nyata berikutnya adalah memeriksa dokumentasi MySQL . Bunyinya:
MySQL menerima dan menampilkan nilai TIME dalam format 'hh: mm: ss' (atau dalam format 'hhh: mm: ss' untuk nilai per jam yang besar).
Sejauh ini, semuanya baik-baik saja: nilai TIME yang bermasalah cocok dengan format ini, meskipun fakta bahwa
hhmereka hhhditentukan secara eksplisit menimbulkan kecurigaan (bagaimana dengan nilai clock yang melebihi 999?). Kalimat berikutnya dalam dokumentasi sebagian menjelaskan semuanya, di sepanjang jalan yang menstimulasi banyak pertanyaan seperti "Apa ...?":
Nilai TIME dapat berkisar dari '-838: 59: 59' hingga '838: 59: 59'.
Baiklah ... Beberapa kisaran yang aneh. Pasti ada alasan teknis yang bagus untuk ini. 839 jam adalah 34,958 (3) hari, dan seluruh rentang tepat 6040798 detik. Dokumentasinya berbunyi sebagai berikut:
MySQL mengenali nilai TIME dalam beberapa format, beberapa di antaranya dapat menyertakan detik pecahan hingga 6 tempat desimal (mikrodetik).
Dengan kata lain, seluruh interval adalah 6.040.798.000.000 mikrodetik. Sekali lagi, angka yang aneh. Ini jauh dari kekuatan dua (antara 2 42 dan 2 43 ), jadi MySQL tampaknya menggunakan beberapa format representasi internal yang unik. Tetapi sebelum saya membahas masalah ini, izinkan saya menunjukkan seberapa buruk tipe ini.
Hanya inilah yang ditawarkan MySQL untuk mengukur interval waktu, dengan seluruh rentang waktu hanya sedikit di atas satu bulan. Seberapa besar "sedikit" ini? Seperti yang Anda lihat, ini bahkan bukan kelipatan dari bilangan bulat hari.
Lebih buruk lagi, MySQL paling populer di penyedia EF Core mengubah .NET
TimeSpanmenjadi TIME secara default , meskipun faktanyaTimeSpandapat berisi interval puluhan ribu tahun (menggunakan bilangan bulat 64-bit, dan presisi yang dapat diterima adalah 10 -8 d). Bandingkan ini dengan beberapa bulan dalam TIME. Orang lain mengalami
masalah ini , dan diskusi di masalah terkait berisi referensi ke perilaku SQL Server: "Ini meniru perilaku SQL Server". Saya memeriksa - memang, jenis waktu SQL Server memiliki rentang dari 00: 00: 00.0000000 hingga 23: 59: 59.9999999, yang umumnya jauh lebih masuk akal daripada rentang TIME yang aneh. Tapi mari kembali ke MySQL. Apa alasan rentang yang tidak biasa itu? Di manual perangkat MySQL
mengatakan bahwa di versi 5.6.4 jenis TIME telah berubah dan ada dukungan untuk sepersekian detik. Tiga byte digunakan untuk keseluruhan bagian. Jika ketiga byte ini digunakan seluruhnya untuk menyandikan detik, ini menghasilkan rentang waktu lebih dari 2.330 jam - jauh lebih banyak daripada maksimum saat ini 838 jam (meskipun itu tidak terlalu berguna saat mengubah
TimeSpan'a).
Ini berarti bahwa proses yang menyandikan waktu di MySQL membuang-buang bit - mungkin demi kemudahan penggunaan (meskipun saya tidak yakin dalam situasi apa ini relevan). Mungkin ini masuk akal jika DBMS (dan ide pengembang tentang apa yang akan dilakukan pengguna dengannya) diarahkan untuk bekerja dengan string, dan pengembang ingin mempercepat presentasi
hh:mm:ss.
Jadi lihat:
1 โ (1 = , 0 = )
1 ( )
10 โ (0-838)
6 โ (0-59)
6 โ (0-59)
โ 24 = 3
Itu menjelaskan segalanya, bukan? Baiklah, mari kita lihat lebih dekat. 10 bit untuk berjam-jam ... dan kisarannya dari nol hingga 838. Saya segera mengingatkan Anda bahwa 2 10 = 1024, bukan 838. Intriknya mendapatkan momentum ...
Tentu saja, saya bukan orang pertama yang menanyakan pertanyaan ini (saya sudah menanyakannya di StackOverflow ). Semuanya tampaknya dinyatakan dalam jawaban "diterima" di sana, namun, pilihan aneh 838 jam pertama kali dijelaskan oleh "kompatibilitas mundur dengan aplikasi yang ditulis cukup lama", dan baru kemudian disebutkan bahwa ini ada hubungannya dengan kompatibilitas dengan MySQL 3 - omong-omong Windows 98 kemudian dianggap sebagai hal baru, dan Linux bahkan belum berusia 10 tahun.
Di MySQL 3, tipe TIME juga menggunakan 3 byte, hanya saja itu melakukannya dengan cara yang sama sekali berbeda. Salah satu bit juga disediakan untuk tanda, tetapi 23 bit sisanya sesuai dengan bilangan bulat, diperoleh sebagai berikut: jam ร 10.000 + menit ร 100 + detik. Dengan kata lain, dua digit paling signifikan adalah detik, dua digit berikutnya adalah menit, dan dua sisanya adalah jam. 2 * 23 adalah 83888608, yaitu 838: 86: 08, jadi nilai waktu valid maksimum dalam format ini adalah 838: 59: 59.
Format ini bahkan kurang nyaman daripada yang sekarang, karena membutuhkan perkalian dan pembagian untuk hampir semua operasi waktu (dengan pengecualian pemformatan dan penguraian string - yang sekali lagi membuktikan bahwa MySQL terlalu memperhatikan string IO dan tidak terlalu peduli dengan keberadaan tipe. yang akan nyaman untuk operasi internal dan protokol berbasis non-string).
Pengembang MySQL telah dapat memperbaiki jenis ini berkali-kali, atau setidaknya memberikan alternatif yang bebas dari batasan yang ada. Jenis TIME telah berubah dua kali dari MySQL 3 hingga hari ini, tetapi setiap kali rentang yang aneh tetap sama - mungkin karena alasan kompatibilitas.
Saya bingung membayangkan situasi di mana memperluas jangkauan nilai untuk suatu tipe dapat merusak kompatibilitas aplikasi: apakah tipe di MySQL memiliki perilaku overflow tertentu? Pemrogram waras apa yang akan bergantung pada batasan internal tipe DB untuk memvalidasi sesuatu dalam aplikasi mereka? Jika ada orang seperti itu, mengapa dia tiba-tiba memutuskan untuk mentransfer batas 838 jam yang konyol ini ke dalam model data aplikasinya tanpa perubahan apa pun? Sejujurnya, saya bahkan tidak ingin mengetahui jawaban atas pertanyaan-pertanyaan ini.
Meskipun ada beberapa transformasi besar dalam sejarah MySQL, tipe TIME masih canggung dan terbatas. Dan sorotan dari program di sini, menurut pendapat saya, adalah bagian yang tidak terpakai "disediakan untuk ekstensi yang akan datang." Saya berharap dalam jangka panjang ini akan menunjuk ke nilai WAKTU lama yang lama, dan pada saat itu MySQL dan / atau MariaDB akan memiliki jenis waktu yang masuk akal seperti INTERVAL di PostgreSQL , yang memiliki rentang ยฑ 178.000.000 tahun dan mikrodetik ketepatan.
PS dari penerjemah
Baca juga di blog kami: