Sqlite: CURRENT_TIMESTAMP ist in GMT, nicht in der Zeitzone der Maschine

118

Ich habe eine SQLite (v3) -Tabelle mit dieser Spaltendefinition:

"timestamp" DATETIME DEFAULT CURRENT_TIMESTAMP

Der Server, auf dem diese Datenbank lebt, befindet sich in der CST-Zeitzone. Wenn ich in meine Tabelle einfüge, ohne die Zeitstempelspalte einzuschließen, füllt sqlite dieses Feld automatisch mit dem aktuellen Zeitstempel in GMT und nicht mit CST.

Gibt es eine Möglichkeit, meine Einfügeanweisung so zu ändern, dass der gespeicherte Zeitstempel in CST angezeigt wird? Auf der anderen Seite ist es wahrscheinlich besser, sie in GMT zu speichern (falls die Datenbank beispielsweise in eine andere Zeitzone verschoben wird). Gibt es also eine Möglichkeit, meine ausgewählte SQL zu ändern, um den gespeicherten Zeitstempel in CST zu konvertieren, wenn ich aus der Tabelle extrahieren?

BrianH
quelle
24
Das Speichern von Zeitstempeln in UTC gilt als bewährte Methode. Konvertieren Sie bei der Präsentation in die Ortszeit .
CSL
2
POSIX definiert Zeitstempel als UTC: stackoverflow.com/a/34107910/895245
Ciro Santilli 5 冠状 病 六四.
1
Ich bin mir nicht sicher, ob diese Art von Problemen bei anderen Arten von Datenbanken auftritt. Sie können sich vorstellen, dass Sie die Daten in Großbritannien verwenden könnten, wenn Sie eine Datenbank in Japan erstellen!
NoChance

Antworten:

145

Ich habe in der SQLite-Dokumentation ( https://www.sqlite.org/lang_datefunc.html ) diesen Text gefunden:

Berechnen Sie Datum und Uhrzeit mit einem Unix-Zeitstempel 1092941466 und kompensieren Sie Ihre lokale Zeitzone.

SELECT datetime(1092941466, 'unixepoch', 'localtime');

Das sah nicht so aus, als würde es meinen Bedürfnissen entsprechen, also habe ich versucht, die "datetime" -Funktion ein wenig zu ändern, und bin zu folgendem Ergebnis gekommen:

select datetime(timestamp, 'localtime')

Das scheint zu funktionieren - ist das der richtige Weg, um für Ihre Zeitzone zu konvertieren, oder gibt es einen besseren Weg, dies zu tun?

BrianH
quelle
64

Verwenden Sie einfach die Ortszeit als Standard:

CREATE TABLE whatever(
     ....
     timestamp DATE DEFAULT (datetime('now','localtime')),
     ...
);
hoju
quelle
5
Dies hat das Problem, nicht über Zeitzonen hinweg übertragbar zu sein, nicht wahr?
Vadim Peretokin
Ja, es funktioniert auch nicht für mich. Ich verwende SQLite in ZF2
Rohutech
@iconoclast sollte es nicht gefährlich sein, wenn Sie sich dessen bewusst sind und wenn es Ihre Implementierung erleichtert, sollte es? Wenn dies das ist, was ich nur brauche, um die lokale Zeitzone in der Datenbank zu speichern, und ich weiß, dass meine Anwendung niemals einen anderen Weg brauchen wird, dann werde ich es tun.
Ahad
1
@xFighter Ich weiß, dass meine Anwendung niemals einen anderen Weg benötigen wird ... Bis Sie das vergessen oder jemand anderes sie verwendet.
MKesper
16

Sie sollten in der Regel Zeitstempel in der Datenbank in GMT belassen und diese nur bei der Eingabe / Ausgabe in / von der Ortszeit konvertieren, wenn Sie sie in den lokalen Zeitstempel des Benutzers (nicht des Servers) konvertieren können.

Es wäre schön, wenn Sie Folgendes tun könnten:

SELECT DATETIME(col, 'PDT')

... um den Zeitstempel für einen Benutzer bei pazifischer Sommerzeit auszugeben. Das funktioniert leider nicht. Gemäß diesem SQLite-Lernprogramm (scrollen Sie nach unten zu "Andere Datums- und Zeitbefehle") können Sie jedoch nach der Uhrzeit fragen und gleichzeitig einen Versatz (in Stunden) anwenden. Wenn Sie also den Zeitzonenversatz des Benutzers kennen, sind Sie gut.

Beschäftigt sich jedoch nicht mit Sommerzeitregeln ...

Roger Lipscombe
quelle
15

In dem (zugegebenermaßen seltenen) Fall, dass eine lokale Datenzeit gewünscht wird (ich speichere beispielsweise die Ortszeit in einer meiner Datenbanken, da es mir nur darum geht, wie spät es am Tag ist und ich nicht verfolge, wo ich war In Bezug auf Zeitzonen ...) können Sie die Spalte als definieren

"timestamp" TEXT DEFAULT (strftime('%Y-%m-%dT%H:%M','now', 'localtime'))

Der Teil% Y-% m-% dT% H:% M ist natürlich optional; So möchte ich, dass meine Zeit gespeichert wird. [Wenn mein Eindruck korrekt ist, gibt es in SQLite keinen Datentyp "DATETIME". Es spielt also keine Rolle, ob TEXT oder DATETIME als Datentyp in der Spaltendeklaration verwendet wird.]

mehrsprachig
quelle
Die SQLite-Ortszeit ist in Zeitstempeln und in Anwendungen, in denen der Endbenutzer die Daten nicht direkt über ein BI-Tool verwendet, möglicherweise weniger wichtig. Die Ortszeit ist jedoch das, was Sie verwenden müssen, um alle anwendungsspezifischen Daten wie das Geburtsdatum zu speichern.
NoChance
9

Wenn eine Spalte mit " NOT NULL DEFAULT CURRENT_TIMESTAMP," definiert ist , werden eingefügte Datensätze immer mit der UTC / GMT-Zeit festgelegt.

Folgendes habe ich getan, um zu vermeiden, dass die Zeit in meine INSERT / UPDATE-Anweisungen aufgenommen werden muss:

--Create a table having a CURRENT_TIMESTAMP:
CREATE TABLE FOOBAR (
    RECORD_NO INTEGER NOT NULL,
    TO_STORE INTEGER,
    UPC CHAR(30),
    QTY DECIMAL(15,4),
    EID CHAR(16),
    RECORD_TIME NOT NULL DEFAULT CURRENT_TIMESTAMP)

--Create before update and after insert triggers:
CREATE TRIGGER UPDATE_FOOBAR BEFORE UPDATE ON FOOBAR
    BEGIN
       UPDATE FOOBAR SET record_time = datetime('now', 'localtime')
       WHERE rowid = new.rowid;
    END

CREATE TRIGGER INSERT_FOOBAR AFTER INSERT ON FOOBAR
    BEGIN
       UPDATE FOOBAR SET record_time = datetime('now', 'localtime')
       WHERE rowid = new.rowid;
    END

Testen Sie, ob es funktioniert ...

--INSERT a couple records into the table:
INSERT INTO foobar (RECORD_NO, TO_STORE, UPC, PRICE, EID)
    VALUES (0, 1, 'xyz1', 31, '777')

INSERT INTO foobar (RECORD_NO, TO_STORE, UPC, PRICE, EID)
    VALUES (1, 1, 'xyz2', 32, '777')

--UPDATE one of the records:
UPDATE foobar SET price = 29 WHERE upc = 'xyz2'

--Check the results:
SELECT * FROM foobar

Hoffentlich hilft das.

Donal Fellows
quelle
1
Unterscheidet sich dies von der Antwort des Benutzers hoju, CREATE TABLE, was auch immer (.... timestamp DATE DEFAULT (datetime ('now', 'localtime')) ,.);?
NoChance
7
SELECT datetime('now', 'localtime');
Flüssigkeit
quelle
6

SELECT datetime(CURRENT_TIMESTAMP, 'localtime')

Jens A. Koch
quelle
4

Sie können die Zeitspalte auch einfach mit strftime () in einen Zeitstempel konvertieren:

SELECT strftime('%s', timestamp) as timestamp FROM ... ;

Gibt Ihnen:

1454521888

Die Tabellenspalte 'Zeitstempel' kann auch ein Textfeld sein, wenn Sie current_timestampals STANDARD verwenden.

Ohne Zeit:

SELECT timestamp FROM ... ;

Gibt Ihnen:

2016-02-03 17:51:28

Gefahr89
quelle
3

Ich denke, das könnte helfen.

SELECT datetime(strftime('%s','now'), 'unixepoch', 'localtime');
Alex
quelle
für unxitime; SELECT strftime ('% s', 'now', 'localtime');
PodTech.io
1

Time ( 'now', 'localtime' )und Datum ( 'now', 'localtime' )funktioniert.

julianisch
quelle