Sqlite: CURRENT_TIMESTAMP está em GMT, não o fuso horário da máquina

118

Eu tenho uma tabela sqlite (v3) com esta definição de coluna:

"timestamp" DATETIME DEFAULT CURRENT_TIMESTAMP

O servidor em que este banco de dados reside está no fuso horário CST. Quando insiro em minha tabela sem incluir a coluna de carimbo de data / hora, o sqlite preenche automaticamente esse campo com o carimbo de data / hora atual em GMT, não CST.

Existe uma maneira de modificar minha instrução de inserção para forçar o carimbo de data / hora armazenado em CST? Por outro lado, provavelmente é melhor armazená-lo em GMT (no caso de o banco de dados ser movido para um fuso horário diferente, por exemplo), então há uma maneira de modificar meu SQL selecionado para converter o carimbo de data / hora armazenado em CST quando eu extraí-lo da mesa?

BrianH
fonte
24
Armazenar carimbos de data / hora em UTC é considerada prática recomendada. Converta para a hora local ao apresentá- los.
csl
2
POSIX define os carimbos de data / hora como UTC: stackoverflow.com/a/34107910/895245
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
Não tenho certeza se esse tipo de problema enfrenta outros tipos de bancos de dados. Você imagina que, se criar um banco de dados no Japão, poderá usar os dados no Reino Unido!
NoChance de

Respostas:

145

Encontrei na documentação do sqlite ( https://www.sqlite.org/lang_datefunc.html ) este texto:

Calcule a data e a hora com um carimbo de data / hora unix 1092941466 e compense seu fuso horário local.

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

Isso não parecia atender às minhas necessidades, então tentei mudar um pouco a função "data e hora" e acabei com o seguinte:

select datetime(timestamp, 'localtime')

Isso parece funcionar - é a maneira correta de converter para o seu fuso horário ou existe uma maneira melhor de fazer isso?

BrianH
fonte
64

simplesmente use a hora local como padrão:

CREATE TABLE whatever(
     ....
     timestamp DATE DEFAULT (datetime('now','localtime')),
     ...
);
hoju
fonte
5
No entanto, isso tem o problema de não ser transferível entre fusos horários, não?
Vadim Peretokin,
sim, não está funcionando para mim também, estou usando sqlite no ZF2
Rohutech
@iconoclast não deve ser perigoso se você estiver ciente disso e se isso tornar sua implementação mais fácil, certo? se isso é o que eu preciso apenas para armazenar o fuso horário local no banco de dados e eu sei que meu aplicativo nunca vai precisar de outra maneira, então eu vou.
Ahad
1
@xFighter Eu sei que meu aplicativo nunca vai precisar de outra maneira ... Até que você esqueça disso ou outra pessoa esteja usando.
MKesper de
16

Você deve, como regra, deixar carimbos de data / hora no banco de dados em GMT e apenas convertê-los de / para a hora local na entrada / saída, quando puder convertê-los para o carimbo de data / hora local do usuário (não do servidor).

Seria bom se você pudesse fazer o seguinte:

SELECT DATETIME(col, 'PDT')

... para gerar o carimbo de data / hora para um usuário no horário de verão do Pacífico. Infelizmente, isso não funciona. De acordo com este tutorial SQLite , no entanto (role para baixo até "Outros comandos de data e hora"), você pode solicitar a hora e, em seguida, aplicar um deslocamento (em horas) ao mesmo tempo. Então, se você sabe a diferença de fuso horário do usuário, você está bem.

Não lida com as regras de horário de verão ...

Roger Lipscombe
fonte
15

No (raro admitido) caso em que um datatime local é desejado (eu, por exemplo, armazeno o horário local em um dos meus bancos de dados, pois tudo que me importa é que hora do dia é e não mantenho o controle de onde eu estava em termos de fusos horários ...), você pode definir a coluna como

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

A parte% Y-% m-% dT% H:% M é obviamente opcional; é apenas como gosto que meu tempo seja armazenado. [Além disso, se minha impressão estiver correta, não há tipo de dados "DATETIME" em sqlite, então realmente não importa se TEXT ou DATETIME é usado como tipo de dados na declaração da coluna.]

poliglota
fonte
O sqlite localtime pode ser menos importante em registros de data e hora e em aplicativos onde o usuário final não usa os dados diretamente por meio de uma ferramenta de BI. No entanto, a hora local é o que você precisa usar para armazenar todas as datas específicas do aplicativo, como data de nascimento.
NoChance de
9

Ao ter uma coluna definida com " NOT NULL DEFAULT CURRENT_TIMESTAMP," os registros inseridos sempre serão configurados com o horário UTC / GMT.

Aqui está o que fiz para evitar a necessidade de incluir a hora em minhas instruções 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

Teste para ver se funciona ...

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

Espero que ajude.

Donal Fellows
fonte
1
Isso é diferente da resposta fornecida pelo usuário hoju, CREATE TABLE qualquer (.... timestamp DATE DEFAULT (datetime ('now', 'localtime')),.) ;?
NoChance de
7
SELECT datetime('now', 'localtime');
liquide
fonte
6

SELECT datetime(CURRENT_TIMESTAMP, 'localtime')

Jens A. Koch
fonte
4

Você também pode simplesmente converter a coluna de tempo em um carimbo de data / hora usando strftime ():

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

Da-te:

1454521888

A coluna da tabela 'timestamp' pode ser um campo de texto mesmo, usando current_timestampcomo DEFAULT.

Sem strftime:

SELECT timestamp FROM ... ;

Da-te:

2016-02-03 17:51:28

perigo 89
fonte
3

Eu acho que isso pode ajudar.

SELECT datetime(strftime('%s','now'), 'unixepoch', 'localtime');
Alex
fonte
para não-marítimo; SELECT strftime ('% s', 'agora', 'localtime');
PodTech.io
1

Time ( 'now', 'localtime' )e Data ( 'now', 'localtime' )funciona.

Julian
fonte