Sqlite: CURRENT_TIMESTAMP to GMT, a nie strefa czasowa maszyny

118

Mam tabelę sqlite (v3) z tą definicją kolumny:

"timestamp" DATETIME DEFAULT CURRENT_TIMESTAMP

Serwer, na którym znajduje się ta baza danych, znajduje się w strefie czasowej CST. Kiedy wstawiam do mojej tabeli bez dodawania kolumny timestamp, sqlite automatycznie wypełnia to pole bieżącym znacznikiem czasu w GMT, a nie CST.

Czy istnieje sposób na zmodyfikowanie instrukcji wstawiania, aby wymusić zapisany znacznik czasu w CST? Z drugiej strony, prawdopodobnie lepiej jest przechowywać go w GMT (na przykład w przypadku przeniesienia bazy danych do innej strefy czasowej), więc czy istnieje sposób, aby zmodyfikować mój wybrany SQL, aby przekonwertować zapisany znacznik czasu na CST, kiedy ja wyciągnąć to ze stołu?

BrianH
źródło
24
Przechowywanie znaczników czasu w UTC jest uważane za najlepszą praktykę. Konwertuj na czas lokalny podczas prezentacji .
csl
2
POSIX definiuje znaczniki czasu jako UTC: stackoverflow.com/a/34107910/895245
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
Nie jestem pewien, czy tego rodzaju problemy napotykają inne typy baz danych. Można sobie wyobrazić, że jeśli utworzysz bazę danych w Japonii, możesz użyć danych w Wielkiej Brytanii!
NoChance

Odpowiedzi:

145

W dokumentacji sqlite ( https://www.sqlite.org/lang_datefunc.html ) znalazłem ten tekst:

Oblicz datę i godzinę z uniksowym znacznikiem czasu 1092941466 i zrekompensuj swoją lokalną strefę czasową.

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

To nie wyglądało tak, jakby pasowało do moich potrzeb, więc spróbowałem nieco zmienić funkcję „datetime” i skończyło się na tym:

select datetime(timestamp, 'localtime')

Wydaje się, że to działa - czy to właściwy sposób na konwersję dla Twojej strefy czasowej, czy też jest lepszy sposób na zrobienie tego?

BrianH
źródło
64

po prostu użyj czasu lokalnego jako domyślnego:

CREATE TABLE whatever(
     ....
     timestamp DATE DEFAULT (datetime('now','localtime')),
     ...
);
hoju
źródło
5
Problem polega jednak na tym, że nie można ich przenosić między strefami czasowymi, prawda?
Vadim Peretokin
tak jest, u mnie też nie działa, używam sqlite w ZF2
Rohutech
@iconoclast to nie powinno być niebezpieczne, gdzie, jeśli jesteś tego świadomy i jeśli to ułatwia implementację, czy powinno? jeśli potrzebuję tylko tego do przechowywania lokalnej strefy czasowej w bazie danych i wiem, że moja aplikacja nigdy nie będzie potrzebować innego sposobu, to będę.
Ahad
1
@xFighter Wiem, że moja aplikacja nigdy nie będzie potrzebować innej drogi ... Dopóki o tym nie zapomnisz lub ktoś jej nie użyje .
MKesper
16

Zasadniczo należy pozostawić znaczniki czasu w bazie danych w formacie GMT i konwertować je na czas lokalny / z czasu lokalnego na wejściu / wyjściu tylko wtedy, gdy można je przekonwertować na lokalny znacznik czasu użytkownika (nie serwera).

Byłoby miło, gdybyś mógł wykonać następujące czynności:

SELECT DATETIME(col, 'PDT')

... do wyprowadzenia sygnatury czasowej użytkownika według czasu pacyficznego letniego. Niestety to nie działa. Jednak zgodnie z tym samouczkiem SQLite (przewiń w dół do „Inne polecenia dotyczące daty i godziny”) możesz zapytać o czas, a następnie jednocześnie zastosować przesunięcie (w godzinach). Tak więc, jeśli znasz przesunięcie strefy czasowej użytkownika, jesteś dobry.

Nie zajmuje się jednak zasadami czasu letniego ...

Roger Lipscombe
źródło
15

W (przyznanym rzadkim) przypadku, gdy potrzebny jest lokalny czas danych (na przykład przechowuję czas lokalny w jednej z moich baz danych, ponieważ obchodzi mnie tylko, która godzina była w ciągu dnia i nie śledzę, gdzie byłem pod względem stref czasowych ...), możesz zdefiniować kolumnę jako

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

Część% Y-% m-% dT% H:% M jest oczywiście opcjonalna; po prostu lubię przechowywać swój czas. [Ponadto, jeśli moje wrażenie jest poprawne, w sqlite nie ma typu danych „DATETIME”, więc nie ma znaczenia, czy jako typ danych w deklaracji kolumny jest używany TEXT czy DATETIME.]

poliglota
źródło
sqlite localtime może mieć mniejsze znaczenie w sygnaturach czasowych i aplikacjach, w których użytkownik końcowy nie korzysta z danych bezpośrednio za pośrednictwem narzędzia BI. Jednak czas lokalny jest tym, czego potrzebujesz do przechowywania wszystkich konkretnych dat aplikacji, takich jak data urodzenia.
NoChance
9

Gdy kolumna jest zdefiniowana za pomocą „ NOT NULL DEFAULT CURRENT_TIMESTAMP,” wstawione rekordy będą zawsze ustawiane według czasu UTC / GMT.

Oto, co zrobiłem, aby uniknąć konieczności uwzględniania czasu w moich instrukcjach INSERT / UPDATE:

--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

Sprawdź, czy działa ...

--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

Mam nadzieję, że to pomoże.

Donal Fellows
źródło
1
Czy to różni się od odpowiedzi udzielonej przez użytkownika hoju, CREATE TABLE cokolwiek (.... timestamp DATE DEFAULT (datetime ('now', 'localtime')),.) ;?
NoChance
7
SELECT datetime('now', 'localtime');
płyn
źródło
6

SELECT datetime(CURRENT_TIMESTAMP, 'localtime')

Jens A. Koch
źródło
4

Możesz także po prostu przekonwertować kolumnę czasu na znacznik czasu za pomocą strftime ():

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

Daje Ci:

1454521888

Kolumna tabeli „sygnatura czasowa” może być nawet polem tekstowym, przy użyciu opcji current_timestampDEFAULT.

Bez strftime:

SELECT timestamp FROM ... ;

Daje Ci:

03.02.2016 17:51:28

niebezpieczeństwo 89
źródło
3

Myślę, że to może pomóc.

SELECT datetime(strftime('%s','now'), 'unixepoch', 'localtime');
Alex
źródło
do transportu morskiego; SELECT strftime („% s”, „teraz”, „czas lokalny”);
PodTech.io
1

Time ( 'now', 'localtime' )i Data ( 'now', 'localtime' )działa.

juliański
źródło