Cara terbaik untuk menyimpan waktu (jj: mm) dalam database

100

Saya ingin menyimpan waktu dalam tabel database tetapi hanya perlu menyimpan jam dan menit. Saya tahu saya bisa saja menggunakan DATETIME dan mengabaikan komponen tanggal lainnya, tetapi apa cara terbaik untuk melakukan ini tanpa menyimpan lebih banyak info daripada yang sebenarnya saya butuhkan?

Matthew Dresser
sumber
Apa yang setara dengan TIME untuk sql server 2005?
Erran Morad
@BoratSagdiyev tidak ada satu pun di SQL Server 2005, itulah mengapa saya mengajukan pertanyaan.
Matthew Dresser

Jawaban:

135

Anda dapat menyimpannya sebagai bilangan bulat dari jumlah menit lewat tengah malam:

misalnya.

0 = 00:00 
60 = 01:00
252 = 04:12

Namun Anda perlu menulis beberapa kode untuk mengatur ulang waktu, tetapi itu seharusnya tidak rumit.

BigJump
sumber
8
Kemudian gunakan DATEADD () untuk mendapatkan kembali waktu nyata. Bahkan sekecil apapun akan cukup.
Joel Coehoorn
36
sudah ada, lakukan itu ... menit = dd% 60 dan jam = dd / 60 di ints melakukan trik.
Osama Al-Maadeed
2
Itu ide yang bagus, sederhana, dan lurus. +1
whiskysierra
7
kelemahan kecil adalah kurangnya keterbacaan dalam database
Jowen
kita perlu menyimpan beberapa varian hari, jam dan menit; tipe data Waktu di SQL Server hanya naik ke 23:59:59 jadi kami tidak bisa menggunakannya. Terinspirasi oleh jawaban Anda, kami memutuskan untuk memiliki tiga kolom int untuk hari: jam: menit untuk fleksibilitas maksimum. Terima kasih!
matao
55

Jika Anda menggunakan SQL Server 2008+, pertimbangkan TIMEtipe data. Artikel SQLTeam dengan lebih banyak contoh penggunaan.

WebMatrix
sumber
15

DATETIME mulai DATETIME berakhir

Saya mohon Anda untuk menggunakan dua nilai DATETIME sebagai gantinya, diberi label seperti event_start dan event_end .

Waktu adalah urusan yang kompleks

Sebagian besar dunia sekarang telah mengadopsi sistem metrik berbasis pemandangan untuk sebagian besar pengukuran, benar atau salah. Ini bagus secara keseluruhan, karena setidaknya kita semua bisa sepakat bahwa ag, adalah ml, adalah cm kubik. Setidaknya kira-kira begitu. Sistem metrik memiliki banyak kekurangan, tetapi setidaknya secara internasional selalu cacat.

Namun seiring waktu, kami memiliki; 1000 milidetik dalam satu detik, 60 detik hingga satu menit, 60 menit hingga satu jam, 12 jam untuk setiap setengah hari, kira-kira 30 hari per bulan yang bervariasi menurut bulan dan bahkan tahun yang bersangkutan, setiap negara memiliki waktu yang berbeda dari yang lain , format waktu di setiap negara berbeda-beda.

Banyak yang harus dicerna, tetapi panjang dan pendeknya tidak mungkin skenario serumit itu memiliki solusi sederhana.

Beberapa sudut dapat dipotong, tetapi ada yang lebih bijaksana untuk tidak melakukannya

Meskipun jawaban teratas di sini menunjukkan bahwa Anda menyimpan bilangan bulat menit lewat tengah malam mungkin tampak masuk akal, saya telah belajar untuk menghindari melakukannya dengan cara yang sulit.

Alasan untuk menerapkan dua nilai DATETIME adalah untuk peningkatan akurasi, resolusi, dan umpan balik.

Ini semua sangat berguna ketika desain menghasilkan hasil yang tidak diinginkan.

Apakah saya menyimpan lebih banyak data dari yang dibutuhkan?

Awalnya mungkin tampak seperti lebih banyak informasi disimpan daripada yang saya butuhkan, tetapi ada alasan bagus untuk menerima serangan ini.

Menyimpan informasi tambahan ini hampir selalu menghemat waktu dan tenaga saya dalam jangka panjang, karena saya pasti menemukan bahwa ketika seseorang diberitahu berapa lama sesuatu berlangsung, mereka juga akan ingin tahu kapan dan di mana acara itu terjadi juga.

Itu adalah planet yang sangat besar

Di masa lalu, saya bersalah karena mengabaikan bahwa ada negara lain di planet ini selain negara saya. Sepertinya ide yang bagus pada saat itu, tetapi ini SELALU mengakibatkan masalah, sakit kepala, dan waktu yang terbuang di kemudian hari. SELALU pertimbangkan semua zona waktu.

C #

Sebuah DateTime merender dengan baik ke string di C #. Metode ToString (format string) ringkas dan mudah dibaca.

Misalnya

new TimeSpan(EventStart.Ticks - EventEnd.Ticks).ToString("h'h 'm'm 's's'")

Server SQL

Juga jika Anda membaca database Anda secara terpisah dari antarmuka aplikasi Anda, maka dateTimes menyenangkan untuk dibaca sekilas dan melakukan penghitungan pada mereka sangatlah mudah.

Misalnya

SELECT DATEDIFF(MINUTE, event_start, event_end)

Standar tanggal ISO8601

Jika menggunakan SQLite maka Anda tidak memiliki ini, jadi gunakan bidang Teks dan simpan dalam format ISO8601 mis.

"2013-01-27T12: 30: 00 + 0000"

Catatan:

  • Ini menggunakan format 24 jam *

  • Bagian offset waktu (atau +0000) dari ISO8601 memetakan langsung ke nilai bujur koordinat GPS (tidak memperhitungkan pergeseran waktu siang hari atau seluruh negara).

Misalnya

TimeOffset=(±Longitude.24)/360 

... dimana ± mengacu pada arah timur atau barat.

Oleh karena itu perlu dipertimbangkan apakah perlu menyimpan bujur, lintang dan ketinggian bersama dengan datanya. Ini akan bervariasi dalam penerapannya.

  • ISO8601 adalah format internasional.

  • Wiki sangat bagus untuk detail lebih lanjut di http://en.wikipedia.org/wiki/ISO_8601 .

  • Tanggal dan waktu disimpan dalam waktu internasional dan offset dicatat tergantung di mana di dunia waktu itu disimpan.

Menurut pengalaman saya, selalu ada kebutuhan untuk menyimpan tanggal dan waktu penuh, terlepas dari apakah saya pikir ada saat saya memulai proyek. ISO8601 adalah cara yang sangat bagus dan futureproof untuk melakukannya.

Saran tambahan gratis

Ada baiknya juga mengelompokkan acara bersama seperti sebuah rangkaian. Misalnya, jika merekam balapan, seluruh acara dapat dikelompokkan berdasarkan pembalap, sirkuit_balap, titik pemeriksaan sirkuit, dan sirkuit_lap.

Menurut pengalaman saya, adalah bijaksana juga untuk mengidentifikasi siapa yang menyimpan catatan tersebut. Baik sebagai tabel terpisah yang diisi melalui pemicu atau sebagai kolom tambahan dalam tabel asli.

Semakin banyak Anda memasukkan, semakin banyak Anda keluar

Saya sepenuhnya memahami keinginan untuk menjadi seefisien mungkin dengan ruang, tetapi saya jarang melakukannya dengan mengorbankan informasi yang hilang.

Aturan praktis dengan database adalah seperti judulnya, database hanya dapat memberi tahu Anda sebanyak yang ada datanya, dan bisa sangat mahal untuk kembali melalui data historis, mengisi celah.

Solusinya adalah memperbaikinya pertama kali. Ini tentu lebih mudah diucapkan daripada dilakukan, tetapi Anda sekarang harus memiliki wawasan yang lebih dalam tentang desain database yang efektif dan kemudian memiliki peluang yang jauh lebih baik untuk melakukannya dengan benar pada kali pertama.

Semakin baik desain awal Anda, semakin murah biaya perbaikannya nanti.

Saya hanya mengatakan semua ini, karena jika saya bisa kembali ke masa lalu maka itulah yang akan saya katakan pada diri saya sendiri ketika saya sampai di sana.

WonderWorker
sumber
2
Komentar Anda "Bagian +0000 dari ISO8601 memetakan langsung ke garis lintang dalam koordinat GPS" salah. Ini mewakili offset dari UTC
Gary Walker
10

Simpan saja tanggal waktu biasa dan abaikan yang lainnya. Mengapa menghabiskan waktu ekstra untuk menulis kode yang memuat int, memanipulasinya, dan mengubahnya menjadi datetime, ketika Anda bisa memuat datetime?

Seth
sumber
3
Salah satu kemungkinan alasannya adalah untuk menghemat ruang pada hard drive - DATETIMETipe data membutuhkan 4 byte untuk disimpan, sementara SMALLINTmisalnya, hanya membutuhkan seperempat dari itu. Tidak ada perbedaan besar jika Anda hanya memiliki beberapa ribu baris, tetapi jika Anda memiliki jutaan baris seperti yang dimiliki banyak perusahaan, maka penghematan ruang Anda akan sangat besar.
Sheridan
32
Mungkin, tetapi pertimbangkan bahwa 12 orang menjawab pertanyaan ini, masing-masing membutuhkan, katakanlah, 15 menit untuk memikirkannya. Asumsikan bahwa mereka semua adalah programmer dan menghasilkan $ 50 per jam. Dengan biaya waktu yang dihabiskan hanya untuk memikirkan masalah ini, Anda dapat membeli hard drive 2TB baru yang mengkilap untuk menyimpan byte ekstra.
Seth
@Seth Anda benar jika kita hanya berbicara tentang byte ekstra. Tetapi saran Anda hanya bisa jika itu adalah proyek kecil dengan 1-2 pengembang. Tapi ini akan menjadi proyek besar dengan banyak pengembang (ditambah QA), itu akan menjadi masalah besar ketika programmer baru mencoba mencari tahu. Sayangnya, kita semua bergantung pada logika bisnis.
Mediator
Dengan layanan cloud, menghemat ruang disk menjadi penting jika Anda membayar per byte yang dibaca / diproses.
RedShift
2
Masalah menyenangkan lainnya adalah jika Anda mengandalkan komponen waktu, itu tidak akan memperhitungkan penyesuaian tabungan Daylight bila digunakan pada waktu yang berbeda dalam setahun.
Chris Seufert
4

karena Anda tidak menyebutkannya sedikit jika Anda menggunakan SQL Server 2008 Anda dapat menggunakan tipe data waktu jika tidak menggunakan menit sejak tengah malam

SQLMenace
sumber
3

SQL Server sebenarnya menyimpan waktu sebagai pecahan hari. Misalnya, 1 whole day = nilai 1. 12 hours adalah nilai 0.5.

Jika Anda ingin menyimpan nilai waktu tanpa menggunakan tipe DATETIME, menyimpan waktu dalam bentuk desimal akan sesuai dengan kebutuhan itu, sementara juga membuat konversi ke DATETIME sederhana.

Sebagai contoh:

SELECT CAST(0.5 AS DATETIME)
--1900-01-01 12:00:00.000

Menyimpan nilai sebagai DECIMAL (9,9) akan memakan 5 byte. Namun, jika presisi tidak terlalu penting, REAL hanya akan mengkonsumsi 4 byte. Dalam kedua kasus, penghitungan agregat (yaitu waktu rata-rata) dapat dengan mudah dihitung pada nilai numerik, tetapi tidak pada jenis Data / Waktu.

Taylor Gerring
sumber
"SQL Server sebenarnya menyimpan waktu sebagai pecahan dari satu hari." Saya pikir itu menyimpan hari sejak (atau sebelum) 01-Jan-1900 dalam 4 byte dan waktu pertama, dalam milidetik, dalam 4 byte kedua. (SmallDateTime menggunakan 2 byte untuk masing-masing dengan rentang tanggal yang lebih sempit, dan menit, bukan milidetik untuk waktu)
Kristen
Saya tahu (99,99% yakin) bahwa untuk waktu hari ini adalah pecahan.
graham.reeds
2

Saya akan mengubahnya menjadi integer (HH * 3600 + MM * 60), dan menyimpannya seperti itu. Ukuran penyimpanan kecil, dan masih cukup mudah untuk dikerjakan.

Glen Solsberry
sumber
2

Jika Anda menggunakan MySQL, gunakan jenis bidang TIME dan fungsionalitas terkait yang disertakan dengan TIME.

00:00:00 adalah format waktu unix standar.

Jika Anda harus melihat ke belakang dan meninjau tabel dengan tangan, bilangan bulat bisa lebih membingungkan daripada stempel waktu yang sebenarnya.

Sintaksis
sumber
1

Coba waktu kecil. Ini mungkin tidak memberikan apa yang Anda inginkan tetapi akan membantu kebutuhan Anda di masa depan dalam manipulasi tanggal / waktu.

MarlonRibunal
sumber
jika @mdresser menggunakan <MSSQL 2005 server akan melalui "out-of-range smalldatetime value"
Fergus
1

Apakah Anda yakin Anda hanya membutuhkan jam dan menit? Jika Anda ingin melakukan sesuatu yang berarti dengannya (seperti misalnya rentang waktu komputasi antara dua titik data) tidak memiliki informasi tentang zona waktu dan DST dapat memberikan hasil yang salah. Zona waktu mungkin tidak berlaku dalam kasus Anda, tetapi DST pasti akan berlaku.

mghie
sumber
1

Alih-alih menit lewat tengah malam kami menyimpannya sebagai format 24 jam, sebagai SMALLINT.

09:12 = 912 14:15 = 1415

saat mengonversi kembali ke "bentuk yang dapat dibaca manusia" kami hanya menyisipkan titik dua ":" dua karakter dari kanan. Kiri-pad dengan nol jika perlu. Menyimpan matematika dengan cara apa pun, dan menggunakan beberapa byte lebih sedikit (dibandingkan dengan varchar), ditambah penegakan bahwa nilainya adalah numerik (bukan alfanumerik)

Cukup konyol ... seharusnya sudah ada tipe data TIME di MS SQL selama setahun sudah IMHO ...

Kristen
sumber
Kristen benar sekali, tetapi hanya jika asumsinya tentang jam dan menit hanya mewakili satu periode 24 jam yang benar. 10 bit diperlukan untuk menyimpan 0..1439 menit. Ini berarti ada 6 bit tambahan yang bisa digunakan sesuka Anda, jadi ada ruang untuk berkreasi. Saya sarankan menggunakan 5 bit untuk menyimpan offset jam untuk zona waktu Anda, tetapi hanya jika penanya hanya ingin menyimpan waktu maksimum 23:59 (satu menit hingga tengah malam)
WonderWorker
1

Apa yang saya pikir Anda minta adalah variabel yang akan menyimpan menit sebagai angka. Ini dapat dilakukan dengan berbagai jenis variabel integer:

SELECT 9823754987598 AS MinutesInput

Kemudian, dalam program Anda, Anda cukup melihat ini dalam bentuk yang Anda inginkan dengan menghitung:

long MinutesInAnHour = 60;

long MinutesInADay = MinutesInAnHour * 24;

long MinutesInAWeek = MinutesInADay * 7;


long MinutesCalc = long.Parse(rdr["MinutesInput"].toString()); //BigInt converts to long. rdr is an SqlDataReader.   


long Weeks = MinutesCalc / MinutesInAWeek;

MinutesCalc -= Weeks * MinutesInAWeek;


long Days = MinutesCalc / MinutesInADay;

MinutesCalc -= Days * MinutesInADay;


long Hours = MinutesCalc / MinutesInAnHour;

MinutesCalc -= Hours * MinutesInAnHour;


long Minutes = MinutesCalc;

Masalah muncul ketika Anda meminta efisiensi untuk digunakan. Tapi, jika Anda kekurangan waktu, gunakan saja BigInt nullable untuk menyimpan nilai menit Anda.

Nilai null berarti waktu belum direkam.

Sekarang, saya akan jelaskan dalam bentuk perjalanan pulang pergi ke luar angkasa.

Sayangnya, kolom tabel hanya akan menyimpan satu jenis. Oleh karena itu, Anda perlu membuat tabel baru untuk setiap jenis sesuai kebutuhan.

Sebagai contoh:

  • Jika MinutesInput = 0 .. 255 maka gunakan TinyInt (Ubah seperti dijelaskan di atas).

  • Jika MinutesInput = 256 .. 131071 maka gunakan SmallInt (Catatan: Nilai min SmallInt adalah -32,768. Oleh karena itu, negasikan dan tambahkan 32768 saat menyimpan dan mengambil nilai untuk menggunakan jangkauan penuh sebelum mengonversi seperti di atas).

  • Jika MinutesInput = 131072 .. 8589934591 kemudian gunakan Int (Catatan: Negasikan dan tambahkan 2147483648 seperlunya).

  • Jika MinutesInput = 8589934592 .. 36893488147419103231 kemudian gunakan BigInt (Catatan: Tambahkan dan hapus 9223372036854775808 seperlunya).

  • Jika MinutesInput> 36893488147419103231 maka saya pribadi akan menggunakan VARCHAR (X) meningkatkan X seperlunya karena char adalah byte. Saya harus meninjau kembali jawaban ini di kemudian hari untuk menjelaskan ini secara lengkap (atau mungkin rekan stackoverflowee dapat menyelesaikan jawaban ini).

Karena setiap nilai pasti memerlukan kunci unik, efisiensi database hanya akan terlihat jika kisaran nilai yang disimpan adalah campuran yang baik antara sangat kecil (mendekati 0 menit) dan sangat tinggi (Lebih dari 8589934591).

Sampai nilai yang disimpan benar-benar mencapai angka yang lebih besar dari 36893488147419103231 maka Anda mungkin juga memiliki satu kolom BigInt untuk mewakili menit Anda, karena Anda tidak perlu membuang Int pada pengenal unik dan int lain untuk menyimpan nilai menit.

WonderWorker
sumber
0

Penghematan waktu dalam format UTC dapat membantu lebih baik seperti yang disarankan Kristen.

Pastikan Anda menggunakan jam 24 jam karena tidak ada meridian AM atau PM yang digunakan dalam UTC.

Contoh:

  • 4:12 AM - 0412
  • 10.12 - 1012
  • 14.28 - 1428
  • 11:56 PM - 2356

Ini masih lebih disukai untuk menggunakan format empat digit standar.

balamurugavel
sumber
0

Simpan tickssebagai a long/ bigint, yang saat ini diukur dalam milidetik. Nilai yang diperbarui dapat ditemukan dengan melihat TimeSpan.TicksPerSecondnilainya.

Kebanyakan database memiliki tipe DateTime yang secara otomatis menyimpan waktu sebagai tick di belakang layar, tetapi dalam kasus beberapa database misalnya SqlLite, menyimpan tick dapat menjadi cara untuk menyimpan tanggal.

Kebanyakan bahasa memungkinkan konversi yang mudah dari TicksTimeSpanTicks.

Contoh

Di C # kodenya adalah:

long TimeAsTicks = TimeAsTimeSpan.Ticks;

TimeAsTimeSpan = TimeSpan.FromTicks(TimeAsTicks);

Berhati-hatilah, karena dalam kasus SqlLite, yang hanya menawarkan sejumlah kecil tipe berbeda, yaitu; INT, REALdan VARCHARJumlah kutu perlu disimpan sebagai string atau dua INTsel yang digabungkan. Ini, karena INTadalah nomor bertanda 32bit sedangkan BIGINTnomor bertanda 64bit.

Catatan

Preferensi pribadi saya bagaimanapun, akan menyimpan tanggal dan waktu sebagai ISO8601string.

WonderWorker
sumber
-1

IMHO apa solusi terbaik tergantung sampai batas tertentu pada bagaimana Anda menyimpan waktu di sisa database (dan sisa aplikasi Anda)

Secara pribadi saya telah bekerja dengan SQLite dan mencoba untuk selalu menggunakan stempel waktu unix untuk menyimpan waktu absolut, jadi ketika berhadapan dengan waktu hari (seperti yang Anda minta) saya melakukan apa yang ditulis Glen Solsberry dalam jawabannya dan menyimpan jumlah detik sejak tengah malam

Saat mengambil pendekatan umum ini, orang-orang (termasuk saya!) Membaca kode tidak terlalu bingung jika saya menggunakan standar yang sama di mana-mana

sunyata
sumber