Ini adalah masalah yang saya alami beberapa kali. Bayangkan Anda memiliki catatan yang ingin Anda simpan ke dalam tabel database. Tabel ini memiliki kolom DateTime yang disebut "date_created". Satu catatan khusus ini dibuat sejak lama, dan Anda tidak benar-benar yakin tentang tanggal pastinya, tetapi Anda tahu tahun dan bulan. Catatan lain yang Anda tahu tahun itu. Catatan lain Anda tahu hari, bulan dan tahun.
Anda tidak dapat menggunakan bidang DateTime, karena "Mei 1978" bukan tanggal yang valid. Jika Anda membaginya menjadi beberapa kolom, Anda kehilangan kemampuan untuk bertanya. Adakah orang lain yang mengalami hal ini, jika demikian bagaimana Anda menanganinya?
Untuk memperjelas sistem yang saya bangun, ini adalah sistem yang melacak arsip. Beberapa konten telah diproduksi sejak lama, dan yang kita tahu adalah "Mei 1978". Saya dapat menyimpannya sebagai 1 Mei 1978, tetapi hanya dengan beberapa cara untuk menyatakan bahwa tanggal ini hanya akurat untuk bulan tersebut. Dengan begitu beberapa tahun kemudian ketika saya mengambil arsip itu, saya tidak bingung ketika tanggal tidak cocok.
Untuk tujuan saya, penting untuk membedakan "hari yang tidak diketahui pada bulan Mei 1978" dengan "1 Mei 1978". Juga, saya tidak ingin menyimpan yang tidak dikenal sebagai 0, seperti "0 Mei 1978" karena kebanyakan sistem basis data akan menolak itu sebagai nilai tanggal yang tidak valid.
sumber
Jawaban:
Menyimpan semua tanggal di bidang DATE normal dalam database dan memiliki bidang akurasi tambahan seberapa akurat bidang DATE sebenarnya.
date_created_accuracy: 1 = tanggal pasti, 2 = bulan, 3 = tahun.
Jika kencan Anda tidak jelas (mis. Mei 1980) simpan tanggalnya di awal periode (mis. 1 Mei 1980). Atau jika tanggal Anda akurat untuk tahun (mis. 1980) simpan tanggal 1 Januari. 1980 dengan nilai akurasi yang sesuai.
Cara ini dapat dengan mudah meminta dengan cara yang agak alami dan masih memiliki gagasan tentang seberapa akurat tanggal. Sebagai contoh, ini memungkinkan Anda untuk menanyakan tanggal antara
Jan 1st 1980
danFeb 28th 1981
, dan mendapatkan tanggal fuzzy1980
danMay 1980
.sumber
select * from mytable where date_created between "1980/1/1" and "1981/2/28" and date_created_accuracy <= 2;
. Jenius.date_created_accuracy
bidang. Anda dapat menampilkan "Mei 1980" atau hanya "1980" di hasil atau UI jika seakurat yang ditunjukkan bidang.Jika Anda tidak perlu menggunakan data seperti ini sebagai informasi waktu-tanggal reguler, format string apa pun bisa dilakukan.
Tetapi jika Anda perlu menjaga semua fungsinya, ada dua solusi yang dapat saya pikirkan, keduanya membutuhkan informasi tambahan yang disimpan dalam database:
min date
danmax date
bidang, yang memiliki nilai berbeda untuk data "tidak lengkap", tetapi akan bertepatan untuk tanggal yang akurat.type
bidang ke catatan dan simpan informasi yang hilang.sumber
min date
danmax date
bidang. Saya pikir itu adalah solusi yang paling fleksibel, namun tepat dan mudah digunakan.Ini lebih merupakan definisi persyaratan daripada masalah teknis - yang perlu Anda fokuskan adalah "bagaimana kita dapat menentukan tanggal di masa lalu" dan solusi teknis akan mengalir.
Saat-saat saya harus mendekati sesuatu seperti ini biasanya kami:
Kadang-kadang seseorang perlu melakukan sesuatu seperti membuat tanggal menjadi kabur - misalnya, yang mungkin satu tanggal mungkin perlu menanggapi permintaan untuk apa pun pada Mei 1978. Ini bisa dilakukan - buat saja bidang create_date 2 Anda, catatan lama mendapat 30 hari tersebar sebagaimana mestinya, yang baru mendapatkan 2 nilai yang identik.
sumber
Cara paling sederhana untuk menunjukkan jika tanggal akurat adalah dengan membuat bidang akurasi INT (1) dengan NULL default
Jika tanggal akurat simpan tanggal-waktu di "date_created" & tinggalkan akurasi NULL
Jika tanggal hanya akurat untuk tanggal toko tanggal waktu sebagai 1 Bulan dengan nilai akurasi 1
Jika tanggal hanya akurat untuk tanggal toko tahun waktu 1 Januari dengan nilai akurasi 2
Anda dapat menggunakan angka yang berbeda untuk menyimpan nilai yang berbeda seperti kuartal pertama, dll
sumber
Di masa lalu saya telah menyimpan tanggal-dengan-akurasi sebagai tanggal mulai dan tanggal akhir. Hari may21.2012 akan direpresentasikan sebagai mulai = 12 pagi, 21 Mei 2012 dan akhir = 12 pagi, 22222012. Tahun 2012 akan direpresentasikan sebagai awal = 12 pagi, Jan 1.2012 akhir = 12 pagi, Jan.12013.
Saya tidak yakin apakah saya akan merekomendasikan pendekatan ini. Saat menampilkan informasi kepada pengguna, Anda perlu mendeteksi dengan benar bahwa rentang tanggal persis mencakup satu hari untuk menunjukkan "mungkin 25" alih-alih dua titik akhir yang terlalu spesifik (yang berarti berurusan dengan penghematan siang hari dan sebagainya).
Namun, ketika Anda tidak mencoba menerjemahkan ke manusia, pemrograman dengan titik akhir jauh lebih mudah daripada dengan akurasi pusat +. Anda tidak berakhir dengan banyak kasus. Cukup bagus.
sumber
Mengapa tidak menyimpan dua kurma.
Created_After dan Created_Before. Semantik aktual "dibuat pada atau setelah" dan "dibuat pada atau sebelum"
Jadi jika Anda tahu tanggal pastinya maka Created_After dan Created_Before akan menjadi tanggal yang sama.
Jika Anda tahu itu adalah minggu pertama di bulan Mei 2000 maka Created_After = '2000-05-01' dan Created_Before = '2000-05-07'.
Jika Anda hanya tahu Mei 1999 maka nilainya akan menjadi '1999-05-01' dan '1999-05-30'.
Jika "Summer of '42" maka nilainya akan menjadi '1942-06-01' dan '1942-08-31'.
Skema ini mudah di-query dengan SQL normal, dan cukup mudah diikuti oleh pengguna yang tidak teknis.
Misalnya untuk menemukan semua dokumen yang mungkin telah dibuat pada Mei 2001:
Sebaliknya untuk menemukan semua dokumen yang pasti dibuat pada Mei 2001:
sumber
Format waktu tanggal ISO 8601 hadir dengan definisi durasi, mis
2012-01-01P1M
(baca: 2012, 1 Januari, periode: 1 bulan) adalah apa yang seharusnya “pada Januari 2012”.Saya akan menggunakan ini untuk menyimpan data. Anda mungkin perlu bidang database tipe String untuk melakukannya. Ini adalah topik yang berbeda bagaimana melakukan pencarian yang masuk akal tentang itu.
sumber
Secara umum, saya masih menyimpannya sebagai tanggal ke bisnis kueri umum masih dimungkinkan walaupun sedikit kurang akurat.
Jika penting untuk mengetahui keakuratan yang saya miliki di masa lalu baik menyimpan "jendela" akurasi baik sebagai +/- desimal atau sebagai pencarian (hari, bulan, tahun, dll). Dalam kasus lain, alih-alih jendela, saya hanya menyimpan nilai tanggal asli sebagai string dan mengonversi apa yang saya bisa ke datetime, mungkin 1978-05-01 00:00:00 dan "Mei 1978" untuk contoh Anda.
sumber
Kata siapa? Inilah yang Anda lakukan:
Jadi jika saya melakukan penyisipan seperti:
insert into thistable (Day, Month, Year) values (-1, 2, 2012);
maka TheDate akan menjadi 2/1/2013 tetapi saya akan tahu ini benar-benar tanggal yang tidak ditentukan pada 2/2012 karena -1 di bidang Day.Jika saya
insert into thistable (TheDate) values ('2/5/2012');
maka Hari akan menjadi 5, Bulan akan menjadi 2, dan Tahun akan menjadi 2012 dan karena tidak satupun dari mereka adalah -1, saya akan tahu ini adalah tanggal yang tepat.Saya tidak kehilangan kemampuan untuk bertanya karena pemicu sisipan / pembaruan memastikan 3 bidang saya (Hari, Bulan, Tahun) selalu menghasilkan nilai DateTime di TheDate yang dapat ditanyakan.
sumber
Pilihan lain adalah menyimpan tanggal sebagai bilangan bulat dari formulir
YYYYMMDD
.19510000
19510300
19510314
0
Manfaat
Anda dapat menyimpan tanggal fuzzy Anda dalam satu bidang alih-alih dua bidang tanggal atau tanggal dan akurasi seperti yang disarankan oleh banyak jawaban lainnya.
Pertanyaan masih mudah:
SELECT * FROM table WHERE thedate>=19510000 and thedate<19520000
SELECT * FROM table where thedate>=19510300 and thedate<19510400
SELECT * FROM table where thedate=19510314
CATATAN
GetDateString(int fuzzyDate)
yang cukup mudah untuk diterapkan.99
'padding' alih-alih00
untuk bulan atau hari.sumber
ISO 8601 juga menentukan sintaks untuk "tanggal fuzzy". 12 Februari 2012 jam 3 sore adalah "2012-02-12T15" dan Februari 2012 bisa jadi "2012-02". Ini meluas dengan baik menggunakan penyortiran leksikografis standar:
sumber
Inilah pendapat saya tentang ini:
Mulai dari fuzzy date ke objek datetime (yang akan masuk ke dalam database)
Dan kemudian fungsi yang mengambil objek datetime, dan memindahkannya kembali ke tanggal fuzzy.
Dan kemudian tes unit. Apakah saya melewatkan kasus?
Ada kasus sudut di mana peristiwa yang terjadi secara tepat
2001-01-01T00:00:00.333333
tetapi sistem akan menafsirkan sebagai hanya "2001", tetapi itu tampaknya sangat tidak mungkin.sumber
Saya bekerja untuk sebuah perusahaan penerbitan yang berurusan dengan banyak buku-buku tua di mana kita sering tidak bisa mendapatkan tanggal pasti untuk segala hal. Kami biasanya memiliki dua bidang untuk entri tanggal tertentu, tanggal dan sekitar boolean:
Kami menggunakan bidang tanggal untuk menunjukkan tanggal dari beberapa peristiwa, atau tanggal yang "cukup dekat" dalam kasus di mana kami tidak tahu tanggal yang sebenarnya. Jika kami tidak mengetahui tanggal sebenarnya, kami menandai
dateCirca
bidang sebagaiY
dan memberikan tanggal yang cukup dekat, yang ditandai sebagai "tanggal 1", sepertisumber
Gambaran
Ada banyak kemungkinan representasi, dan dengan demikian skema database, untuk menyimpan tanggal fuzzy (atau bahkan hanya tanggal fuzzy):
[1], [2], dan [3] adalah semua interval seragam (secara implisit), yaitu seperangkat (sama) poin yang mungkin dalam waktu.
[4] adalah yang paling ekspresif, yaitu ketika memungkinkan kalimat atau frasa bahasa tertulis yang memungkinkan (atau setidaknya panjang). Tapi itu juga yang paling sulit untuk dikerjakan. Dalam batas tersebut, AI tingkat manusia akan diperlukan untuk menangani nilai-nilai sewenang-wenang. Secara praktis, kisaran nilai yang mungkin perlu dibatasi secara ketat, dan nilai 'terstruktur' alternatif mungkin akan lebih disukai untuk banyak operasi, misalnya penyortiran, pencarian.
[5] mungkin merupakan representasi kompak paling umum yang (agak) praktis.
Interval Seragam
Interval yang seragam adalah cara ringkas paling sederhana untuk mewakili sekumpulan nilai waktu tanggal (mungkin).
Untuk [1], bagian-bagian dari nilai tanggal-waktu diabaikan, yaitu bagian-bagian yang terkait dengan unit yang lebih halus daripada presisi atau akurasi yang ditunjukkan; jika tidak, ini setara dengan [2] dan kode presisi / keakuratan setara dengan interval dengan unit yang sama (dan kuantitas tersirat dari 1).
[2] dan [3] secara ekuivalen setara. [1] sangat kurang ekspresif daripada karena ada interval efektif yang tidak dapat diwakili oleh [1], mis. tanggal-waktu fuzzy setara dengan interval 12 jam yang mencakup batas tanggal.
[1] lebih mudah bagi pengguna untuk memasukkan daripada representasi lainnya dan umumnya harus (setidaknya sedikit) kurang mengetik. Jika tanggal-waktu dapat dimasukkan dalam berbagai representasi teks, misalnya "2013", "2014-3", "2015-5-2", "7/30/2016 11p", "2016-07-31 18:15" , ketepatan atau keakuratan juga dapat disimpulkan secara otomatis dari input.
Keakuratan atau ketepatan [1] juga paling mudah untuk dikonversi ke formulir yang akan disampaikan kepada pengguna, misalnya '2015-5 dengan akurasi bulan' hingga "Mei 2015", dibandingkan "13 Mei 2015 2p, plus atau minus 13,5 hari" (perhatikan bahwa yang terakhir tidak dapat diwakili oleh [1] lagipula).
String
Secara praktis, nilai-nilai string perlu dikonversi ke representasi lain untuk kueri, mengurutkan, atau membandingkan beberapa nilai. Jadi, sementara bahasa alami (manusia) apa pun tertulis lebih ekspresif daripada [1], [2], [3], atau [5], kami belum memiliki cara untuk menangani lebih dari sekadar representasi atau format teks standar. Mengingat itu, ini mungkin representasi yang paling tidak berguna dengan sendirinya .
Salah satu keuntungan dari representasi ini adalah bahwa nilai-nilai harus, dalam praktiknya, dapat ditampilkan kepada pengguna apa adanya dan tidak memerlukan transformasi agar mudah dipahami.
Distribusi Probabilitas
Distribusi probabilitas menggeneralisasi representasi interval yang seragam [1], [2], [3], dan (bisa dibilang) setara dengan representasi string (umum) [4].
Salah satu keuntungan dari distribusi probabilitas dibandingkan string adalah bahwa yang pertama tidak ambigu.
[5-1] akan sesuai untuk nilai-nilai yang (sebagian besar) sesuai dengan distribusi yang ada, misalnya output nilai tanggal-waktu dari perangkat yang pengukurannya diketahui (atau dipikirkan) agar sesuai dengan distribusi tertentu.
[5-2] mungkin cara terbaik (agak) praktis untuk secara kompak mewakili nilai 'fuzzy datetime'. Tentu saja komputabilitas dari distribusi probabilitas khusus menggunakan hal-hal dan pasti ada masalah yang menarik (dan mungkin tidak mungkin) untuk dipecahkan ketika menanyakan, menyortir, atau membandingkan nilai-nilai yang berbeda, tetapi banyak dari ini mungkin sudah diketahui atau diselesaikan di suatu tempat pada saat ini literatur matematika dan statistik jadi ini jelas berdiri sebagai representasi yang sangat umum dan tidak ambigu.
sumber
Saya sangat menyukai solusi James Anderson - Membatasi tanggal secara akurat adalah cara untuk mendapatkan struktur permintaan yang paling fleksibel. Cara lain untuk mencapai hal yang sama adalah dengan menggunakan start, end atau bahkan pusat
date
plusinterval
(tersedia setidaknya di PostgreSQL , Oracle dan SQLAlchemy ).sumber
Dalam kasus Anda, Anda hanya perlu tahun, bulan, dan hari. Tahun dan bulan diperlukan, hari adalah opsional. Saya akan menggunakan sesuatu seperti itu:
Plus, Anda masih dapat menggunakan indeks dengan sangat efektif. Antrian (kecil = minus, mendapatkan sedikit lebih "rumit" (lebih lama).
sumber
1978-??-31
?Saya hanya akan menyimpan waktu yang tepat untuk tanggal normal dan membuat bagian waktu dari tanggal fuzzy generik seperti 00:00:00. Saya kemudian akan membuat semua tanggal fuzzy tanggal 1 bulan itu.
Saat Anda bertanya, Anda
Ada solusi yang lebih baik dari ini, tetapi saya pribadi benci metadata (data tentang data saya). Itu hanya memiliki kebiasaan keluar dari tangan setelah beberapa saat.
sumber