Mengapa tidak mengembalikan tanggal sebagai string dari database?

41

Dalam aplikasi web tipikal, tanggal diambil dari lapisan basis data yang diketik dengan kuat (mis. Dalam c # sebagai System.DateTime sebagai lawan System.String).

Ketika suatu tanggal perlu dinyatakan sebagai string (misalnya ditampilkan pada halaman), konversi dari DateTime ke string dilakukan di tingkat presentasi.

Kenapa ini? Mengapa hal yang buruk untuk mengubah DateTime ke string pada tingkat basis data?

Lihat juga debat panas dalam obrolan , dan pertanyaan awal yang memulai semua ini .

John Wu
sumber
73
Izinkan saya bertanya kepada Anda: apakah Anda kemudian akan mengkonversi setiap jenis tunggal ke string? Apa yang membuat Date berbeda?
gardenhead
7
Pertanyaan bagus! Silakan lihat debat panas yang sedang berlangsung, di sini .
John Wu
8
Sepertinya cukup jelas bahwa orang itu salah, dan yang lainnya benar. Bukan pertanyaan di sini
gardenhead
7
Terkadang Anda perlu melakukan matematika tanggal di luar basis data. Jauh lebih sulit jika yang Anda miliki hanyalah string.
Eric King
14
Masalah lain - apa jenis string yang Anda butuhkan? Ada BANYAK cara untuk merepresentasikan datetime sebagai string. Bagaimana jika saya memiliki database yang hanya mengembalikan waktu saat ini, diwakili sebagai # detik sejak zaman, sebagai string (misalnya, waktu saat ini adalah "1474496980"). Apakah itu berguna? Apakah Anda ingin menggunakan database seperti itu?
riwalk

Jawaban:

168

Tanggal, DateTimes, dan benar-benar objek yang diketik lainnya, umumnya harus dibiarkan dalam format yang diketik dengan benar sampai saat Anda membutuhkannya untuk dibuat menjadi beberapa jenis lainnya - terutama ketika jenis itu adalah bentuk yang dapat dibaca manusia, dan terutama ketika itu merupakan lossy / konversi satu arah.

Mengapa? Karena diasumsikan bahwa tipe tersebut memberi Anda banyak fungsionalitas bawaan yang praktis, seperti pengujian kesetaraan yang tepat, penambahan dan pengurangan, perbandingan (lebih besar dari, kurang dari), zona waktu dan fungsionalitas lokal (terutama penting untuk apa pun yang berkaitan dengan waktu), dll. Jika Anda memutuskan ingin mendukung orang Amerika dan format "Hari Bulan [Tahun], Tahun" serta gaya umum Inggris "Hari Bulan Tahun", atau standar ISO "Tahun-Bulan-Hari"? Apa yang akan Anda lakukan jika itu adalah string dan Anda perlu melakukan perubahan itu, menguraikannya kembali menjadi Tanggal? Ugh, tidak, terima kasih - ada banyak kejahatan dan bug pengecut seperti itu, yang sebaiknya dihindari sepenuhnya.

Lebih khusus, Anda menyebutkan arsitektur berjenjang, yang memiliki lapisan presentasi terpisah dari data nanti. Ini sebenarnya adalah alasan besar lainnya untuk melewatkan Tanggal sebagai Tanggal dan bukan string - karena jenis format string mana yang harus dimasukkan tanggal? Bahasa Inggris, Mandarin, dengan atau tanpa detik / milidetik, nama atau digit bulan penuh, akankah Anda ingin mengurutkan pada bidang tanggal nanti (menyortir string menuntut format string tertentu jika Anda ingin berfungsi dengan benar), dll? Ini semua pertanyaan presentasi - bagaimana pengguna harus melihat data - dan menempatkan logika itu di tempat lain akan membatasi keuntungan memiliki arsitektur berjenjang di tempat pertama. Basis data tidak perlu tahu atau peduli bagaimana Anda ingin melihat tanggal di masa depan.

Akhirnya, hampir semua aplikasi yang kompleks (untuk apa arsitektur berjenjang) yang peduli dengan waktu pasti akan menggunakan waktu / tanggal dalam banyak, banyak cara, dan seringkali pada semua tingkat arsitektur yang berbeda. Objek yang diketik terkait dengan waktu dan tanggal ada untuk alasan yang sangat bagus: waktu itu sendiri, dan terutama sistem kalender manusia, aneh dan sulit. Pada akhirnya, waktu dan tanggal bukanlah string untuk alasan yang sama dengan bilangan bulat dan floating point bukan string, dan itu hanya akan membuat hidup Anda lebih sulit jika Anda mencoba berpura-pura bahwa mereka benar-benar hanya array karakter, karena sebenarnya tidak.

BrianH
sumber
26
+1 hanya karena menggunakan kata pengecut. Saya setuju dengan argumen Anda yang meyakinkan dan penjelasan komprehensif, tapi itu sebabnya saya harus masuk dan memilih Anda.
Adrian Larson
1
Mewakili datetime sebagai detik karena waktu yang ditentukan di masa lalu juga kuat di antara berbagai kalender. Misalnya kalender Islam dan Cina tidak menggunakan bulan-bulan Greogrian, angka tahun, dll. Saya akan mempertimbangkan untuk menangani ini di tingkat basis data sebagai praktik yang buruk.
rexkogitans
Tanggal sering disajikan sebagai "X hari yang lalu". Semoga berhasil mengurai itu kembali ke nilai asli.
Agent_L
5
Mari kita juga tidak melupakan masalah perubahan DST (dan yang serupa lainnya). Akankah "6 Nov 2016 01:30:26" menjadi yang pertama atau kedua kalinya bahwa tanggal dan waktu ini akan terjadi? UTC DateTime setidaknya unik dan Anda selalu dapat menerjemahkannya ke representasi lokal untuk saat itu - kembali dengan cara lain tidak selalu memungkinkan.
J ...
3
Why? Because it is assumed that the type provides you with lots of handy built in functionalityMenurut saya ini hanya sekunder. Alasan sebenarnya adalah bahwa tipe memberi tahu Anda apa itu sesuatu . Sebuah tanggal bukanlah sebuah string, itu hanya terjadi dengan mudah menerjemahkan ke dalam string yang dapat dibaca manusia.
Doval
53

Dia mengatakan untuk menggunakan server web untuk mengubah waktu data menjadi string. Saya mengatakan melakukannya di server database dan bukan server web. Menurut Anda mengapa itu lebih baik? - Kepala MT

Saya ingin tahu tipenya.

Saya benar-benar tidak peduli jika database Anda menyimpan informasi dalam sebuah string, beberapa int, atau byte, karena, pada akhirnya itu selalu byte. String yang mengambil lebih banyak ruang daripada yang dibutuhkan dalam database Anda tidak mengganggu saya. Yang mengganggu saya adalah berkencan seperti ini:

11/10/2016

Dan tidak tahu apakah itu bulan kesebelas atau bulan kesepuluh.

Tapi itu divalidasi katamu. Tentu Anda memasukkannya melalui proses validasi. Tanggalnya benar sekali. Tapi di sini saya mempertahankan hal ini dan yang saya tahu adalah tanggal adalah sebuah string. Aku bahkan tidak bisa memberitahumu tanggal berapa ini.

"Hari kesepuluh November dalam dua ribu enam belas tahun junjungan kita."

Itu sebuah string. Salah satu presentasi kami membutuhkannya dalam format itu. Anda bilang database mengubah semua tanggal menjadi string, kan? Bersenang-senanglah dengan itu.

Pekerjaan basis data adalah menyimpan data bukan menyajikan data. Tentu, Anda bisa melakukannya dalam string tetapi kemudian Anda harus menguraikannya agar berguna untuk disajikan untuk format lain. Menyimpannya dalam bentuk parsing standar untuk jenis apa pun yang ditawarkan DB membuat kita hampir siap untuk menyajikannya tanpa membuat keputusan presentasi. Tidak masalah bagi saya jika DB mendukung tipe itu dengan string atau ints atau bytes. Selama ia tahu apa yang dilakukannya.

Tetapi ketika Anda tidak memberi tahu DB kami sedang berurusan dengan kencan dan menyimpan tanggal sebagai string, Anda secara prematur menyajikan dan memilih satu presentasi daripada yang lainnya. Ini memaksa semua presenter lain untuk menguraikan sebelum mengkonversi. Tidak, basis data bukan bagian dari lapisan presentasi. Jangan memintanya.

Demikian juga lapisan presentasi bukan bagian dari database sehingga tidak bijaksana untuk memasangkan laporan ke detail basis data. Jauh lebih tangguh untuk bertindak berdasarkan tipe.

candied_orange
sumber
Jawaban ini membahas penyimpanan sebagai string. Namun, itu tidak membahas pola umum menyimpan tanggal dalam tipe tanggal asli, tetapi kemudian memformatnya menjadi string dalam query SQL , menggunakan fungsi seperti CONVERT (T-SQL), atau bahwa DBMS biasanya membuat serialisasi tanggalnya menjadi string dalam format yang dapat dikonfigurasi apa pun kueri. Sebagai contoh: postgresql.org/docs/9.5/static/…
dcorking
Itu laporan. Itu terjadi setelah penyimpanan. Seperti mengubah tanggal lahir saya menjadi usia saya.
candied_orange
2
Saya hanya ingin mendorong Anda untuk memperluas jawaban Anda, karena topik OP adalah bagaimana "tanggal diambil dari lapisan basis data". Ada pola yang sudah mapan, meskipun bisa dibilang usang, di mana laporan meminta basis data untuk string tanggal yang diformat dan dilokalkan. Saya pikir OP ingin mendengar argumen penghinaan itu. Saya tahu saya akan melakukannya.
dcorking
@dcorking note pembaruan.
candied_orange
+1 menambahkan lebih banyak air ke pabrik: buat saja sistem pada pangkalan terpasang yang membentang beberapa zona waktu di mana instan absolut adalah yang terpenting dan lihat seberapa baik Anda melakukannya dengan string <-> konversi cap waktu di mana-mana. Terburuk, buat titik perpanjangan bagi orang-orang untuk membuat plugin sendiri dan beri mereka cap waktu ketika string melihat seberapa konsisten cap waktu ini!
Newtopian
19

Lokal

Konversi tanggal ke string untuk keperluan presentasi memerlukan mengetahui preferensi pengguna, karena tanggal yang sama persis umumnya harus ditampilkan secara berbeda untuk pengguna di berbagai lokal. Bahkan jika Anda menggunakan satu lokal di aplikasi Anda, perilaku yang tepat harus menggunakan lokal aplikasi alih-alih server database; dan mereka tidak dijamin identik bahkan jika saat ini mereka secara kebetulan cocok.

Konversi dari tipe tanggal universal ke string spesifik lokal harus terjadi di lapisan presentasi karena itu lapisan yang tahu bagaimana konversi harus dilakukan.

Peter adalah
sumber
3
Untuk contoh kehidupan nyata dari ketidakcocokan lokal, bayangkan menulis aplikasi untuk Maine, pengguna AS dan kemudian di-host di farm server pantai barat Amazon. ;) Sebenarnya ini bukan situasi yang tidak mungkin.
jpmc26
@ jpmc26 Saya tidak mengerti perbedaannya - apakah Maine menggunakan format tanggal yang berbeda untuk seluruh AS?
Pete Kirkham
2
@PeteKirkham Maine dan pantai barat AS menggunakan zona waktu yang berjarak 3 jam.
jpmc26
1
Atau skenario kehidupan nyata lainnya: Bayangkan menjalankan server di Swiss yang harus melayani klien dalam empat (Jerman, Perancis, Italia, Inggris) bahasa yang berbeda dengan lokal yang berbeda (dan aturan pemformatan yang sedikit berbeda). Semoga berhasil memilih lokasi yang tepat untuk server Anda dalam situasi seperti itu.
Voo
1
@ jpmc26 zona waktu dan lokal bukanlah hal yang sama. Misalnya, kami memiliki kantor di Glasgow Skotlandia, Atlanta USA dan Pune India. Konsultan di kantor-kantor ini pada gilirannya memonitor situs (kampus, rumah sakit, hotel dll) di seluruh dunia sepanjang waktu. Basis data aplikasi berfungsi dalam UTC tetapi menampilkan waktu dalam waktu lokal untuk situs yang dimonitor. Konsultan AS memiliki tanggal yang dilokalkan ke MM / DD / YYYY tetapi lokal Inggris dan India adalah DD / MM / YYYY - ini tergantung pada lokal, bukan zona waktu situs atau pengguna.
Pete Kirkham
9

Ini tidak diinginkan karena alasan yang sama Anda tidak akan hanya ingin secara diam-diam mengubah tipe apa pun menjadi string segera setelah menyentuh tier aplikasi. Ada kemungkinan besar Anda akan ingin menggunakan objek itu dalam beberapa cara sebelum menyajikannya kepada pengguna (jika Anda bahkan mempresentasikannya kepada pengguna). Untuk contoh khusus ini, bayangkan Anda perlu melakukan matematika tanggal pada objek. Tidak ada kerugian untuk hanya mengkonversi objek ke string tepat sebelum Anda menampilkannya.

kepala kebun
sumber
4

Jenis ada karena suatu alasan, jika mereka menambahkan tidak ada manfaat maka kita tidak akan memilikinya dan tidak akan menggunakannya dan kita hanya akan memiliki "jenis" dan semuanya akan seperti itu. Mereka tidak hanya nyaman tetapi juga menambah keamanan dan efisiensi. Berikut ini adalah daftar mengapa Anda harus selalu bertahan mengetik dalam format asli mereka dan bukan sebagai string . Saya menggunakan DateTimesebagai contoh sebagian besar waktu tetapi prinsip yang sama berlaku untuk semua tipe primitif seperti bilangan bulat, desimal, biner, dll.


Penyimpanan data

Kendala

Ketik Kendala

Hampir semua penyimpanan data memungkinkan untuk menentukan batasan pada data, ini termasuk batasan tipe. Salah satu manfaat utama dari menentukan DateTimecontoh adalah bahwa data yang disimpan akan dibatasi untuk jenis itu. Tidak akan mungkin untuk memasukkan apa pun selain waktu tanggal terlepas dari bagaimana data dimasukkan ke dalam toko. Yang terakhir ini penting untuk sistem yang lebih besar di mana ada beberapa proses yang berinteraksi langsung dengan toko. Ini juga termasuk mencoba menambahkan tanggal yang salah seperti 30 Februari, (tahun apa saja) karena Februari hanya dapat memiliki 29 hari pada tahun kabisat dan 28 hari untuk tahun tidak kabisat.

Kendala Validasi

Ada juga kendala validasi yang dapat diimplementasikan di Data Store seperti memastikan bahwa tanggal yang dimasukkan tidak melebihi tanggal saat ini atau bahwa tanggal mulai terjadi sebelum tanggal akhir.

Operasi

Sebagian besar penyimpanan data juga memiliki operasi / fungsi seperti DateAddatau DatePartdi MS Sql Server. Ini memungkinkan Anda untuk mulai memfilter atau memilih data tertentu saat data masih tersimpan (belum diambil ke aplikasi).

Format yang diterima secara universal

Dengan menggunakan tipe asli, pengembang atau sistem lain yang juga berinteraksi dengan toko tidak harus diberi tahu tentang detail kecil tentang bagaimana tipe primitif itu disimpan. Ini bukan kasus jika tipe itu disimpan sebagai string, maka Anda harus memastikan bahwa semua orang memahami format DateTimerepresentasi string itu. Sistem ini menjadi rapuh ketika berurusan dengan data yang mencakup lokal, wilayah, dan budaya dalam asal data, lokasi fisik aplikasi, dan atribut pengguna akhir / sistem yang berinteraksi dengan data tersebut. Contoh: format tanggal di satu negara mungkin MM / dd / yyyy (seperti di AS) tetapi di negara lain bisa jadi dd / MM / yyyy, mendeteksi perbedaan itu menjadi hampir mustahil.

Kecepatan

Kecepatan pengambilan, kecepatan validasi, kecepatan operasi dan efisiensi penyimpanan juga merupakan faktor penting. Contoh kecepatan pengambilan: penyimpanan data memungkinkan untuk indeks pada kolom dan indeks ini umumnya dapat lebih efisien digunakan jika jenis disimpan dalam format aslinya.

Aplikasi

Akses data

Mengeksekusi kueri terhadap toko menjadi lebih mudah menggunakan sistem tipe asli karena pengembang, sekali lagi, tidak perlu menebak format penyimpanan. Hampir semua penyedia aplikasi penyimpanan data ( contoh: ado.net ) menyediakan mekanisme untuk membuat kueri parameterisasi yang tepat berdasarkan tipe asli yang disahkan. Berikut adalah contoh menambahkan bagian Tanggal ke kueri ado.net terhadap toko Server Sql, melakukan hal yang sama dengan string akan sangat rumit dan rapuh / rentan kesalahan.

command.Parameters.Add(new SqlParameter("@startDate", SqlDbType.Date) {Value = myDateInstance.Date});

Operasi

Tipe asli dalam kode juga menyediakan operasi standar seperti tipe .net System.Date. Operasi biasanya bersifat matematis seperti menambahkan tanggal, menemukan perbedaan antara tanggal, dll. Sekali lagi, ini tidak mungkin dilakukan dengan mudah pada tipe string.

Lapisan presentasi

Lokal

Ketika tipe primitif akhirnya dikonversi ke string di lapisan presentasi ( lokasi yang benar dalam tumpukan program untuk melakukannya ) programmer sekarang memiliki berbagai opsi untuk menampilkannya dengan benar sesuai dengan konteks di mana ia disajikan. Konteks ini umumnya terdiri dari makna aktual data dan lokal pengguna.

Contoh 1

Contoh datetime dapat diformat secara otomatis berdasarkan lokal pengguna.

DateTime.Now.ToString("D", CultureInfo.GetCultureInfo(userContext.Culture))
Contoh 2

Contoh desimal dapat mewakili jumlah (mata uang) dan lokal pengguna kemudian harus juga menampilkan jumlah sesuai dengan preferensi mereka. Aplikasi c # kemudian dapat menampilkan nilai menggunakan

amount.ToString("C", CultureInfo.GetCultureInfo(userContext.Culture))

Ini bisa menjadi kritis karena budaya yang berbeda menampilkan angka secara berbeda. Pada periode AS (.) Dan koma (,) memiliki makna terbalik yang tepat seperti di Belanda.

Lokasi

Ini sangat spesifik untuk DateTimeinstance. Tanggal dan waktu merupakan kejadian pada saat tertentu dalam waktu tetapi ini biasanya harus disampaikan / disajikan kepada pengguna tergantung pada zona waktu mereka sendiri. Contoh: sebuah DateTimeinstance 2016-09-21T23:38:21.399Zdapat ditampilkan 9/21/2016 5:21 PMuntuk pengguna di Zona Waktu Timur di AS. Ada banyak cara untuk mencapai ini tetapi menjadi hampir mustahil jika instance waktu tanggal disimpan dalam memori sebagai tipe string atau dalam penyimpanan data sebagai tipe string.


Peraturan umum

2 aturan umum untuk sebuah aplikasi mengikuti ketika datang untuk mengkonversi tipe primitif apa pun ke representasi string adalah seperti ini

  • Ketika menerima input, konversi input tersebut ke tipe primitif yang benar sedini mungkin dalam tumpukan program (biasanya di lapisan presentasi)
  • Saat mengambil data untuk ditampilkan, konversikan data itu ke representasi string selambat mungkin dalam tumpukan program (sekali lagi, biasanya di lapisan presentasi)
Igor
sumber
0

Tidak ada yang salah dengan melakukan ini (itu dilakukan sepanjang waktu dalam layanan) selama Anda menggunakan format yang tidak ambigu untuk kencan Anda. Dengan jelas, maksud saya bukan saja tanggalnya jelas (mis. MM / DD vs. DD / MM) tetapi juga zona waktu yang digunakan. Jadi di muka, jika Anda akan merepresentasikan tanggal sebagai teks, gunakan format ISO . Saya sangat suka string waktu berdasarkan UTC.

Pro:

  • String berdasarkan tanggal / waktu bersifat portabel dan mudah dimengerti
  • Seringkali tanggal dalam DB mengandung komponen waktu. Jika ini tidak berarti bagi data Anda, ini sebenarnya dapat menyederhanakan banyak hal.

Kekurangan:

  • Ukuran data. Format internal suatu tanggal dalam suatu DB umumnya akan menggunakan ruang yang jauh lebih sedikit daripada String yang merender tanggal itu.
  • Anda biasanya ingin memasukkannya ke struktur tanggal atau waktu nyata pada klien sehingga mungkin ada waktu tambahan dalam penguraian.

Jika seseorang berkata mereka ingin melakukan ini, saya akan bertanya "mengapa?" karena tidak banyak gunanya. Jika alasan seseorang ingin mengembalikan tanggal sebagai String adalah karena mereka hanya akan menampilkannya secara langsung, ini bukan alasan yang baik untuk menggunakan Strings dari DB.

JimmyJames
sumber