Sqlite: CURRENT_TIMESTAMP находится в GMT, а не в часовом поясе машины

118

У меня есть таблица sqlite (v3) с этим определением столбца:

"timestamp" DATETIME DEFAULT CURRENT_TIMESTAMP

Сервер, на котором находится эта база данных, находится в часовом поясе CST. Когда я вставляю в свою таблицу, не включая столбец метки времени, sqlite автоматически заполняет это поле текущей меткой времени в GMT, а не в CST.

Есть ли способ изменить мой оператор вставки, чтобы сохранить сохраненную метку времени в CST? С другой стороны, вероятно, лучше сохранить его в GMT (например, на случай, если база данных будет перемещена в другой часовой пояс), поэтому есть ли способ изменить свой выбранный SQL для преобразования сохраненной метки времени в CST, когда я извлечь это из таблицы?

BrianH
источник
24
Лучшей практикой считается хранение меток времени в формате UTC. Преобразование в местное время при представлении их.
csl,
2
POSIX определяет временные метки как UTC: stackoverflow.com/a/34107910/895245
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
Не уверен, что с подобными проблемами сталкиваются другие типы баз данных. Вы можете представить, что если вы создадите базу данных в Японии, вы сможете использовать данные в Великобритании!
NoChance

Ответы:

145

Я нашел в документации sqlite ( https://www.sqlite.org/lang_datefunc.html ) этот текст:

Вычислите дату и время, используя временную метку UNIX 1092941466, и компенсируйте местный часовой пояс.

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

Это не выглядело так, как будто это соответствовало моим потребностям, поэтому я попытался немного изменить функцию datetime и закончил с этим:

select datetime(timestamp, 'localtime')

Кажется, это работает - это правильный способ преобразования для вашего часового пояса или есть лучший способ сделать это?

BrianH
источник
64

просто используйте местное время по умолчанию:

CREATE TABLE whatever(
     ....
     timestamp DATE DEFAULT (datetime('now','localtime')),
     ...
);
hoju
источник
5
Однако у этого есть проблема с невозможностью переноса через часовые пояса, не так ли?
Вадим Перетокин
да, у меня это тоже не работает, я использую sqlite в ZF2
Rohutech
@iconoclast это не должно быть опасно, если вы знаете об этом и если это упрощает вашу реализацию, не так ли? если это то, что мне нужно только для сохранения местного часового пояса в базе данных, и я знаю, что моему приложению никогда не понадобится другой способ, тогда я буду.
Ахад
1
@xFighter Я знаю, что моему приложению никогда не понадобится другой способ ... Пока вы не забудете об этом или его не использует кто-то другой.
MKesper
16

Как правило, вы должны оставлять метки времени в базе данных в GMT и преобразовывать их только в / из местного времени при вводе / выводе, когда вы можете преобразовать их в локальную метку времени пользователя (а не сервера).

Было бы неплохо, если бы вы могли сделать следующее:

SELECT DATETIME(col, 'PDT')

... для вывода метки времени пользователя по тихоокеанскому летнему времени. К сожалению, это не работает. Однако, согласно этому руководству по SQLite (прокрутите вниз до «Другие команды даты и времени»), вы можете запросить время, а затем одновременно применить смещение (в часах). Итак, если вы знаете смещение часового пояса пользователя, все в порядке.

Однако не имеет отношения к правилам перехода на летнее время ...

Роджер Липскомб
источник
15

В (признанном редком) случае, когда требуется локальное время данных (я, например, храню местное время в одной из своих баз данных, так как все, что меня волнует, это то, какое время дня было, и я не отслеживаю, где я был с точки зрения часовых поясов ...), вы можете определить столбец как

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

Часть% Y-% m-% dT% H:% M, конечно, необязательна; это то, как я хочу, чтобы мое время сохранялось. [Кроме того, если мое впечатление верное, в sqlite нет типа данных "DATETIME", поэтому на самом деле не имеет значения, используется ли TEXT или DATETIME в качестве типа данных в объявлении столбца.]

полиглот
источник
sqlite localtime может быть менее важным для отметок времени и в приложениях, где конечный пользователь не использует данные напрямую через инструмент бизнес-аналитики. Однако местное время - это то, что вам нужно использовать для хранения всех конкретных дат приложения, таких как дата рождения.
NoChance
9

Если столбец определен с помощью " NOT NULL DEFAULT CURRENT_TIMESTAMP," для вставленных записей всегда устанавливается время UTC / GMT.

Вот что я сделал, чтобы не указывать время в моих операторах 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

Проверьте, работает ли это ...

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

Надеюсь, это поможет.

Donal Fellows
источник
1
Отличается ли это от ответа, предоставленного пользователем hoju, CREATE TABLE any (.... timestamp DATE DEFAULT (datetime ('now', 'localtime')),.);
NoChance
6

SELECT datetime(CURRENT_TIMESTAMP, 'localtime')

Йенс А. Кох
источник
4

Вы также можете просто преобразовать столбец времени в метку времени с помощью strftime ():

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

Дает тебе:

1454521888

Столбец таблицы timestamp может быть даже текстовым полем, используя current_timestampкак DEFAULT.

Без strftime:

SELECT timestamp FROM ... ;

Дает тебе:

2016-02-03 17:51:28

danger89
источник
3

Думаю, это может помочь.

SELECT datetime(strftime('%s','now'), 'unixepoch', 'localtime');
Alex
источник
для unxitime; ВЫБРАТЬ strftime ('% s', 'сейчас', 'местное время');
PodTech.io
1

Time ( 'now', 'localtime' )и Дата ( 'now', 'localtime' )работает.

юлианский
источник