Beste Möglichkeit, Zeit (hh: mm) in einer Datenbank zu speichern


100

Ich möchte Zeiten in einer Datenbanktabelle speichern, muss aber nur die Stunden und Minuten speichern. Ich weiß, ich könnte einfach DATETIME verwenden und die anderen Komponenten des Datums ignorieren, aber wie geht das am besten, ohne mehr Informationen zu speichern, als ich tatsächlich benötige?


Was entspricht TIME für SQL Server 2005?
Erran Morad

@BoratSagdiyev gibt es in SQL Server 2005 keine, deshalb habe ich die Frage gestellt.
Matthew Dresser

Antworten:


135

Sie können es als Ganzzahl der Anzahl der Minuten nach Mitternacht speichern:

z.B.

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

Sie müssten jedoch Code schreiben, um die Zeit wiederherzustellen, aber das sollte nicht schwierig sein.


8
Verwenden Sie dann DATEADD (), um die Echtzeit zurück zu bekommen. Auch Smallint wäre genug.
Joel Coehoorn

36
dort gewesen, getan, dass ... Minuten = dd% 60 und Stunden = dd / 60 auf Ints den Trick macht.
Osama Al-Maadeed

2
Das ist eine großartige, einfache und unkomplizierte Idee. 1
whiskeysierra

7
Ein kleiner Nachteil ist die mangelnde Lesbarkeit in der Datenbank
Jowen

wir müssen eine Variante von Tagen, Stunden und Minuten speichern; Der Datentyp "Zeit" in SQL Server reicht nur bis 23:59:59, sodass wir ihn nicht verwenden konnten. Inspiriert von Ihrer Antwort haben wir uns für drei int-Spalten für Tage entschieden: Stunden: Minuten für maximale Flexibilität. Vielen Dank!
Matao


15

DATETIME start DATETIME end

Ich bitte Sie, stattdessen zwei DATETIME-Werte zu verwenden, die mit event_start und event_end gekennzeichnet sind .

Zeit ist ein komplexes Geschäft

Der größte Teil der Welt hat inzwischen das auf Verweigerung basierende metrische System für die meisten Messungen zu Recht oder zu Unrecht übernommen. Dies ist insgesamt gut, da wir uns zumindest alle einig sein können, dass ag, ein ml, ein Kubikzentimeter ist. Zumindest ungefähr so. Das metrische System weist viele Mängel auf, ist aber zumindest international durchweg fehlerhaft.

Mit der Zeit haben wir jedoch; 1000 Millisekunden in einer Sekunde, 60 Sekunden bis eine Minute, 60 Minuten bis eine Stunde, 12 Stunden für jeden halben Tag, ungefähr 30 Tage pro Monat, die je nach Monat und sogar Jahr variieren. Jedes Land hat seine Zeit von anderen versetzt Die Art und Weise, wie die Zeit in jedem Land formatiert wird, variiert.

Es ist viel zu verdauen, aber das lange und kurze ist für ein so komplexes Szenario unmöglich, eine einfache Lösung zu finden.

Einige Ecken können geschnitten werden, aber es gibt solche, bei denen es klüger ist, dies nicht zu tun

Obwohl die beste Antwort hier darauf hindeutet, dass Sie eine Ganzzahl von Minuten nach Mitternacht speichern, scheint dies durchaus vernünftig zu sein, habe ich gelernt, dies auf die harte Tour zu vermeiden.

Die Gründe für die Implementierung von zwei DATETIME-Werten liegen in einer Erhöhung der Genauigkeit, Auflösung und Rückmeldung.

Diese sind alle sehr praktisch, wenn das Design unerwünschte Ergebnisse liefert.

Speichere ich mehr Daten als erforderlich?

Es mag zunächst so aussehen, als würden mehr Informationen gespeichert, als ich benötige, aber es gibt einen guten Grund, diesen Treffer zu erzielen.

Das Speichern dieser zusätzlichen Informationen spart mir auf lange Sicht fast immer Zeit und Mühe, da ich unweigerlich feststelle, dass jemand, der erfährt, wie lange etwas gedauert hat, zusätzlich wissen möchte, wann und wo die Veranstaltung stattgefunden hat.

Es ist ein riesiger Planet

In der Vergangenheit habe ich mich schuldig gemacht, ignoriert zu haben, dass es neben meinen eigenen noch andere Länder auf diesem Planeten gibt. Es schien damals eine gute Idee zu sein, aber dies hat IMMER zu Problemen, Kopfschmerzen und späterer Zeitverschwendung geführt. Berücksichtigen Sie IMMER alle Zeitzonen.

C #

Eine DateTime lässt sich gut in eine Zeichenfolge in C # rendern. Die ToString-Methode (String Format) ist kompakt und einfach zu lesen.

Z.B

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

SQL Server

Auch wenn Sie Ihre Datenbank separat von Ihrer Anwendungsoberfläche lesen, ist dateTimes auf einen Blick lesbar und die Durchführung von Berechnungen ist unkompliziert.

Z.B

SELECT DATEDIFF(MINUTE, event_start, event_end)

ISO8601 Datumsstandard

Wenn Sie SQLite verwenden, haben Sie dies nicht. Verwenden Sie stattdessen ein Textfeld und speichern Sie es im ISO8601-Format, z.

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

Anmerkungen:

  • Dies verwendet die 24-Stunden-Uhr *

  • Der Zeitversatzteil (oder +0000) der ISO8601 wird direkt dem Längengradwert einer GPS-Koordinate zugeordnet (ohne Berücksichtigung der Sommerzeit oder landesweit).

Z.B

TimeOffset=(±Longitude.24)/360 

... wobei ± sich auf die Ost- oder Westrichtung bezieht.

Es lohnt sich daher zu überlegen, ob es sich lohnt, Längen-, Breiten- und Höhenangaben zusammen mit den Daten zu speichern. Dies variiert in der Anwendung.

  • ISO8601 ist ein internationales Format.

  • Das Wiki ist sehr gut für weitere Details unter http://en.wikipedia.org/wiki/ISO_8601 .

  • Das Datum und die Uhrzeit werden in internationaler Zeit gespeichert und der Versatz wird abhängig davon aufgezeichnet, wo auf der Welt die Uhrzeit gespeichert wurde.

Nach meiner Erfahrung muss immer das vollständige Datum und die vollständige Uhrzeit gespeichert werden, unabhängig davon, ob ich denke, dass dies der Fall ist, wenn ich mit dem Projekt beginne. ISO8601 ist eine sehr gute und zukunftssichere Methode.

Zusätzliche Beratung kostenlos

Es lohnt sich auch, Ereignisse wie eine Kette zusammenzufassen. Wenn Sie beispielsweise ein Rennen aufzeichnen, kann das gesamte Ereignis nach Racer, Race_Circuit, Circuit_checkpoints und Circuit_Laps gruppiert werden.

Nach meiner Erfahrung ist es auch ratsam zu identifizieren, wer die Aufzeichnung gespeichert hat. Entweder als separate Tabelle, die über den Trigger ausgefüllt wird, oder als zusätzliche Spalte in der Originaltabelle.

Je mehr Sie eingeben, desto mehr steigen Sie aus

Ich verstehe den Wunsch, möglichst sparsam mit dem Platz umzugehen, vollkommen, aber ich würde dies selten auf Kosten des Informationsverlusts tun.

Als Faustregel für Datenbanken gilt, wie der Titel schon sagt, dass eine Datenbank nur so viel aussagen kann, wie sie Daten enthält, und dass es sehr kostspielig sein kann, historische Daten erneut zu durchsuchen und Lücken zu schließen.

Die Lösung besteht darin, es beim ersten Mal richtig zu machen. Dies ist sicherlich leichter gesagt als getan, aber Sie sollten jetzt einen tieferen Einblick in das effektive Datenbankdesign haben und anschließend eine viel bessere Chance haben, es beim ersten Mal richtig zu machen.

Je besser Ihr ursprüngliches Design ist, desto kostengünstiger sind die Reparaturen später.

Ich sage das alles nur, denn wenn ich in die Vergangenheit reisen könnte, würde ich es mir sagen, wenn ich dort ankomme.


2
Ihr Kommentar "Der +0000-Teil der ISO8601 ist in einem GPS-Koordinat direkt der Breite zugeordnet" ist falsch. Es stellt den Versatz von UTC dar
Gary Walker

10

Speichern Sie einfach eine reguläre Datums- und Uhrzeitangabe und ignorieren Sie alles andere. Warum zusätzliche Zeit damit verbringen, Code zu schreiben, der ein Int lädt, bearbeitet und in eine Datums- / Uhrzeitangabe konvertiert, wenn Sie nur eine Datums- / Uhrzeitangabe laden könnten?


3
Ein möglicher Grund könnte darin bestehen, Speicherplatz auf der Festplatte zu sparen. Ein DATETIMEDatentyp benötigt 4 Byte zum Speichern, während ein Datentyp SMALLINTbeispielsweise nur ein Viertel davon benötigt. Kein großer Unterschied, wenn Sie nur einige tausend Zeilen haben, aber wenn Sie wie viele Unternehmen viele Millionen Zeilen haben, ist Ihre Platzersparnis erheblich.
Sheridan

32
Möglicherweise, aber bedenken Sie, dass 12 Personen diese Frage beantwortet haben, wobei jede Person beispielsweise 15 Minuten brauchte, um darüber nachzudenken. Angenommen, sie sind alle Programmierer und verdienen 50 US-Dollar pro Stunde. Mit den Kosten für die Zeit, die Sie aufgewendet haben, um über dieses Problem nachzudenken , hätten Sie eine glänzende neue 2-TB-Festplatte kaufen können, um die zusätzlichen Bytes zu speichern.
Seth

@ Seth du hast Recht, wenn wir nur über zusätzliche Bytes sprechen. Ihr Vorschlag kann jedoch nur sein, wenn es sich um ein kleines Projekt mit 1-2 Entwicklern handelt. Aber es wird ein großes Projekt mit vielen Entwicklern (plus Qualitätssicherung). Es wäre ein großes Problem, wenn ein neuer Programmierer versucht, dies herauszufinden. Leider sind wir alle auf Geschäftslogik angewiesen.
Mediator

Bei Cloud-Diensten kann das Einsparen von Speicherplatz wichtig sein, wenn Sie pro gelesenem / verarbeitetem Byte bezahlen.
RedShift

2
Ein weiteres lustiges Problem ist, wenn Sie sich auf die Zeitkomponente verlassen, werden die Sommerzeitanpassungen bei Verwendung zu verschiedenen Jahreszeiten nicht berücksichtigt.
Chris Seufert

4

Da Sie es unter SQL Server 2008 nicht erwähnt haben, können Sie den Datentyp time verwenden, andernfalls Minuten seit Mitternacht


3

SQL Server speichert die Zeit tatsächlich als Bruchteil eines Tages. Zum Beispiel ist 1 ganzer Tag = Wert von 1. 12 Stunden ist ein Wert von 0,5.

Wenn Sie den Zeitwert ohne Verwendung eines DATETIME-Typs speichern möchten, entspricht das Speichern der Zeit in Dezimalform diesen Anforderungen und vereinfacht gleichzeitig die Konvertierung in eine DATETIME.

Beispielsweise:

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

Das Speichern des Werts als DECIMAL (9,9) würde 5 Bytes verbrauchen. Wenn jedoch die Genauigkeit nicht von größter Bedeutung ist, würde ein REAL nur 4 Bytes verbrauchen. In beiden Fällen kann die aggregierte Berechnung (dh die mittlere Zeit) leicht anhand numerischer Werte berechnet werden, nicht jedoch anhand von Daten- / Zeittypen.


"SQL Server speichert die Zeit tatsächlich als Bruchteil eines Tages." Ich denke, es speichert Tage seit (oder vor) dem 01. Januar 1900 in den ersten 4 Bytes und die Zeit in Millisekunden in den zweiten 4 Bytes. (SmallDateTime verwendet 2 Bytes für jedes mit einem engeren Datumsbereich und Minuten anstelle von Millisekunden für die Zeit)
Kristen

Ich weiß (99,99% sicher), dass es für die Tageszeit Brüche sind.
Graham.reeds

2

Ich würde sie in eine ganze Zahl (HH * 3600 + MM * 60) konvertieren und so speichern. Kleine Speichergröße und dennoch einfach zu handhaben.


2

Wenn Sie MySQL verwenden, verwenden Sie einen Feldtyp von TIME und die zugehörige Funktionalität, die mit TIME geliefert wird.

00:00:00 ist das Standard-Unix-Zeitformat.

Wenn Sie jemals zurückblicken und die Tabellen von Hand überprüfen müssen, können Ganzzahlen verwirrender sein als ein tatsächlicher Zeitstempel.


1

Versuchen Sie es mit smalldatetime. Es gibt Ihnen möglicherweise nicht das, was Sie wollen, aber es hilft Ihnen bei Ihren zukünftigen Anforderungen bei Datums- / Zeitmanipulationen.


Wenn @mdresser <MSSQL 2005 verwenden würde, würde der Server den Wert "außerhalb des Bereichs kleiner Datenzeit" durchlaufen
Fergus

1

Sind Sie sicher, dass Sie immer nur die Stunden und Minuten brauchen werden? Wenn Sie damit etwas Sinnvolles tun möchten (wie zum Beispiel Zeitspannen zwischen zwei solchen Datenpunkten berechnen), wenn Sie keine Informationen über Zeitzonen und Sommerzeit haben, kann dies zu falschen Ergebnissen führen. Zeitzonen gelten in Ihrem Fall möglicherweise nicht, die Sommerzeit jedoch mit Sicherheit.


1

Anstelle von Minuten nach Mitternacht speichern wir es als 24-Stunden-Uhr als SMALLINT.

09:12 = 912 14:15 = 1415

Bei der Rückkonvertierung in eine "vom Menschen lesbare Form" fügen wir einfach einen Doppelpunkt ein: "zwei Zeichen von rechts. Linkes Feld mit Nullen, falls erforderlich. Speichert die Mathematik in jeder Richtung und verwendet einige weniger Bytes (im Vergleich zu varchar). Außerdem wird erzwungen, dass der Wert numerisch (und nicht alphanumerisch) ist.

Ziemlich doof ... es sollte schon seit vielen Jahren einen TIME-Datentyp in MS SQL geben, IMHO ...


Kristen ist absolut korrekt, aber nur, wenn ihre Annahme, dass die Stunden und Minuten nur einen einzigen 24-Stunden-Zeitraum darstellen, richtig ist. Zum Speichern von 0..1439 Minuten sind 10 Bits erforderlich. Dies bedeutet, dass es zusätzliche 6 Bits gibt, die nach Belieben verwendet werden können, sodass Sie kreativ werden können. Ich würde vorschlagen, 5 Bit zu verwenden, um den Stundenversatz für die Zeitzone zu speichern, in der Sie sich befinden, aber nur, wenn der Fragesteller nur eine maximale Zeit von 23:59 (eine Minute bis Mitternacht) speichern wollte
WonderWorker

1

Ich denke, Sie fragen nach einer Variablen, die Minuten als Zahl speichert. Dies kann mit den verschiedenen Arten von Ganzzahlvariablen erfolgen:

SELECT 9823754987598 AS MinutesInput

Dann können Sie dies in Ihrem Programm einfach in der gewünschten Form anzeigen, indem Sie Folgendes berechnen:

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;

Ein Problem tritt auf, wenn Sie die Verwendung von Effizienz anfordern. Wenn Sie jedoch wenig Zeit haben, verwenden Sie einfach ein nullbares BigInt, um Ihren Minutenwert zu speichern.

Ein Wert von null bedeutet, dass die Zeit noch nicht aufgezeichnet wurde.

Jetzt werde ich in Form einer Rundreise in den Weltraum erklären.

Leider speichert eine Tabellenspalte nur einen einzigen Typ. Daher müssen Sie für jeden Typ nach Bedarf eine neue Tabelle erstellen.

Beispielsweise:

  • Wenn MinutesInput = 0 .. 255, verwenden Sie TinyInt (Konvertieren wie oben beschrieben).

  • Wenn MinutesInput = 256 .. 131071, verwenden Sie SmallInt (Hinweis: Der Min-Wert von SmallInt beträgt -32.768. Negieren Sie daher 32768 und fügen Sie ihn hinzu, wenn Sie Werte speichern und abrufen, um den gesamten Bereich zu nutzen, bevor Sie wie oben konvertieren).

  • Wenn MinutesInput = 131072 .. 8589934591, verwenden Sie Int (Hinweis: Negieren Sie und fügen Sie bei Bedarf 2147483648 hinzu).

  • Wenn MinutesInput = 8589934592 .. 36893488147419103231, verwenden Sie BigInt (Hinweis: Fügen Sie nach Bedarf 9223372036854775808 hinzu und negieren Sie es).

  • Wenn MinutesInput> 36893488147419103231, würde ich persönlich VARCHAR (X) verwenden, um X nach Bedarf zu erhöhen, da ein Zeichen ein Byte ist. Ich werde diese Antwort zu einem späteren Zeitpunkt noch einmal überprüfen müssen, um sie vollständig zu beschreiben (oder vielleicht kann ein anderer Stackoverflowee diese Antwort beenden).

Da für jeden Wert zweifellos ein eindeutiger Schlüssel erforderlich ist, ist die Effizienz der Datenbank nur dann ersichtlich, wenn der Bereich der gespeicherten Werte eine gute Mischung zwischen sehr klein (nahe 0 Minuten) und sehr hoch (größer als 8589934591) darstellt.

Bis die gespeicherten Werte tatsächlich eine Zahl größer als 36893488147419103231 erreichen, können Sie auch eine einzelne BigInt-Spalte zur Darstellung Ihrer Minuten verwenden, da Sie kein Int für eine eindeutige Kennung und ein anderes int zum Speichern des Minutenwerts verschwenden müssen.


0

Die Zeitersparnis im UTC-Format kann besser helfen, wie Kristen vorgeschlagen hat.

Stellen Sie sicher, dass Sie die 24-Stunden-Uhr verwenden, da in UTC kein Meridian AM oder PM verwendet wird.

Beispiel:

  • 4:12 - 0412
  • 10:12 - 1012
  • 14:28 - 1428
  • 23:56 - 2356

Es ist immer noch vorzuziehen, das vierstellige Standardformat zu verwenden.


0

Speichern Sie die ticksals long/ bigint, die derzeit in Millisekunden gemessen werden. Der aktualisierte Wert kann anhand des TimeSpan.TicksPerSecondWerts ermittelt werden.

Die meisten Datenbanken haben einen DateTime-Typ, der die Uhrzeit automatisch als Ticks hinter den Kulissen speichert. Bei einigen Datenbanken, z. B. SqlLite, kann das Speichern von Ticks eine Möglichkeit sein, das Datum zu speichern.

Die meisten Sprachen ermöglichen die einfache Konvertierung von TicksTimeSpanTicks.

Beispiel

In C # wäre der Code:

long TimeAsTicks = TimeAsTimeSpan.Ticks;

TimeAsTimeSpan = TimeSpan.FromTicks(TimeAsTicks);

Beachten Sie jedoch, dass im Fall von SqlLite nur eine geringe Anzahl verschiedener Typen angeboten wird. INT, REALUnd VARCHARes wird notwendig sein , die Anzahl der Ticks als String oder zwei zu speichern INTZellen kombiniert. Dies liegt daran, dass an INTeine vorzeichenbehaftete 32-Bit-Nummer ist, während BIGINTes sich um eine vorzeichenbehaftete 64-Bit-Nummer handelt.

Hinweis

Meine persönliche Präferenz wäre es jedoch, Datum und Uhrzeit als ISO8601Zeichenfolge zu speichern .


-1

IMHO, was die beste Lösung ist, hängt in gewissem Maße davon ab, wie Sie Zeit im Rest der Datenbank (und im Rest Ihrer Anwendung) speichern.

Persönlich habe ich mit SQLite gearbeitet und versucht, immer Unix-Zeitstempel zum Speichern der absoluten Zeit zu verwenden. Wenn ich mich also mit der Tageszeit befasse (wie Sie es wünschen), mache ich das, was Glen Solsberry in seiner Antwort schreibt, und speichere die Anzahl der Sekunden seit Mitternacht

Bei diesem allgemeinen Ansatz sind die Leute (einschließlich mir!), Die den Code lesen, weniger verwirrt, wenn ich überall den gleichen Standard verwende

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.