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


118

У мене є таблиця sqlite (v3) з визначенням цього стовпця:

"timestamp" DATETIME DEFAULT CURRENT_TIMESTAMP

Сервер, на якому живе ця база даних, знаходиться в часовому поясі CST. Коли я вставляю в свою таблицю, не включаючи стовпець часової позначки, sqlite автоматично заповнює це поле поточною часовою міткою в GMT, а не CST.

Чи є спосіб змінити мій оператор insert, щоб змусити збережену часову позначку бути в CST? З іншого боку, ймовірно, краще зберігати його в GMT (якщо, наприклад, база даних переміщується в інший часовий пояс), тож є спосіб змінити вибраний SQL для перетворення збереженої часової позначки в CST, коли я витягнути його зі столу?


24
Зберігання часових позначок у UTC вважається найкращою практикою. Перетворити на місцевий час при їх представленні .
csl

2
POSIX визначає часові в форматі UTC: stackoverflow.com/a/34107910/895245
Чіро Сантіллі郝海东冠状病六四事件法轮功

1
Не впевнений, чи виникають подібні проблеми з іншими типами баз даних. Ви можете собі уявити, що якщо ви створите базу даних в Японії, ви зможете використовувати дані у Великобританії!
NoChance

Відповіді:


145

Я знайшов у документації sqlite ( https://www.sqlite.org/lang_datefunc.html ) цей текст:

Обчисліть дату та час, надані часовій позначці unix 1092941466, і компенсуйте свій місцевий часовий пояс.

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

Це виглядало не так, як воно відповідає моїм потребам, тому я спробував трохи змінити функцію "datetime" і закінчився цим:

select datetime(timestamp, 'localtime')

Це, здається, працює - це правильний спосіб перетворення для вашого часового поясу, чи є кращий спосіб зробити це?


64

просто використовуйте місцевий час за замовчуванням:

CREATE TABLE whatever(
     ....
     timestamp DATE DEFAULT (datetime('now','localtime')),
     ...
);

5
Однак у цьому проблема не переноситись через часові пояси, ні?
Вадим Перетокін

так, це теж не працює для мене, я використовую sqlite в ZF2
Rohutech

@iconoclast це не повинно бути небезпечно, якщо, якщо ви знаєте про це, і якщо це полегшить вашу реалізацію, чи не так? якщо це те, що мені потрібно тільки для зберігання локального часового поясу в базі даних, і я знаю, що моя програма ніколи не потребуватиме іншого шляху, тоді я буду.
Ахад

1
@xFighter Я знаю, що моя програма ніколи не потребуватиме іншого шляху ... Поки ти не забудеш про це чи хтось іншим не користується цим.
MKesper

16

Як правило, слід залишати часові позначки в базі даних в ГМТ і перетворювати їх у / з місцевого часу лише на час введення / виводу, коли ви можете конвертувати їх у місцеву мітку часу (не на сервері).

Було б добре, якби ви могли зробити наступне:

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 може бути менш важливим у часових марках та в додатках, коли кінцевий користувач не використовує дані безпосередньо через інструмент BI. Однак місцевий час - це те, що потрібно використовувати для зберігання всіх конкретних дат програми, таких як дата народження.
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

Сподіваюся, що це допомагає.


1
Чи відрізняється це від відповіді, наданої користувачем hoju, СТВОРИТИСЯ ТАБЛИЦЮ будь-якою (.... часова марка DATE DEFAULT (datetime ('now', 'localtime')),.) ;?
NoChance



4

Ви також можете просто перетворити стовпець часу у часову позначку, використовуючи strngth ():

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

Дає вам:

1454521888

Стовпець таблиці 'timetamp' може бути навіть текстовим полем, використовуючи current_timestampяк DEFAULT.

Без стропового переривання:

SELECT timestamp FROM ... ;

Дає вам:

2016-02-03 17:51:28


3

Я думаю, це може допомогти.

SELECT datetime(strftime('%s','now'), 'unixepoch', 'localtime');

для непрохідних; SELECT стропінг ('% s', 'now', 'localtime');
PodTech.io


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.