Sqlite: CURRENT_TIMESTAMP est en GMT, pas le fuseau horaire de la machine

119

J'ai une table sqlite (v3) avec cette définition de colonne:

"timestamp" DATETIME DEFAULT CURRENT_TIMESTAMP

Le serveur sur lequel cette base de données vit se trouve dans le fuseau horaire CST. Lorsque j'insère dans ma table sans inclure la colonne d'horodatage, sqlite remplit automatiquement ce champ avec l'horodatage actuel en GMT, pas CST.

Existe-t-il un moyen de modifier mon instruction d'insertion pour forcer l'horodatage stocké à être dans CST? D'un autre côté, il est probablement préférable de le stocker en GMT (au cas où la base de données serait déplacée vers un fuseau horaire différent, par exemple), y a-t-il donc un moyen de modifier mon SQL sélectionné pour convertir l'horodatage stocké en CST lorsque je l'extraire de la table?

BrianH
la source
25
Le stockage des horodatages au format UTC est considéré comme une meilleure pratique. Convertissez en heure locale lors de leur présentation .
csl
2
POSIX définit les horodatages comme UTC: stackoverflow.com/a/34107910/895245
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
Je ne sais pas si ce type de problème est confronté à d'autres types de bases de données. Vous imaginez que si vous créez une base de données au Japon, vous pourriez utiliser les données au Royaume-Uni!
NoChance

Réponses:

146

J'ai trouvé sur la documentation sqlite ( https://www.sqlite.org/lang_datefunc.html ) ce texte:

Calculez la date et l'heure avec un horodatage unix 1092941466 et compensez votre fuseau horaire local.

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

Cela ne semblait pas répondre à mes besoins, alors j'ai essayé de changer un peu la fonction "datetime" et je me suis retrouvé avec ceci:

select datetime(timestamp, 'localtime')

Cela semble fonctionner - est-ce la bonne façon de convertir votre fuseau horaire ou y a-t-il une meilleure façon de le faire?

BrianH
la source
65

utilisez simplement l'heure locale par défaut:

CREATE TABLE whatever(
     ....
     timestamp DATE DEFAULT (datetime('now','localtime')),
     ...
);
hoju
la source
5
Cela pose le problème de ne pas être transférable entre les fuseaux horaires, non?
Vadim Peretokin le
oui ça l'est, ça ne marche pas pour moi non plus, j'utilise sqlite dans ZF2
Rohutech
@iconoclast il ne devrait pas être dangereux où si vous en êtes conscient et si cela facilite votre implémentation, n'est-ce pas? si c'est ce dont j'ai besoin uniquement pour stocker le fuseau horaire local dans la base de données et que je sais que mon application n'aura jamais besoin d'une autre manière, je le ferai.
Ahad
1
@xFighter Je sais que mon application n'aura jamais besoin d'une autre manière ... Jusqu'à ce que vous oubliez cela ou que quelqu'un d'autre l'utilise.
MKesper
16

Vous devez, en règle générale, laisser les horodatages dans la base de données au format GMT et les convertir uniquement vers / depuis l'heure locale en entrée / sortie, lorsque vous pouvez les convertir en horodatage local de l'utilisateur (et non du serveur).

Ce serait bien si vous pouviez faire ce qui suit:

SELECT DATETIME(col, 'PDT')

... pour afficher l'horodatage d'un utilisateur à l'heure avancée du Pacifique. Malheureusement, cela ne fonctionne pas. Cependant, selon ce didacticiel SQLite (faites défiler jusqu'à «Autres commandes de date et d'heure»), vous pouvez demander l'heure, puis appliquer un décalage (en heures) en même temps. Donc, si vous connaissez le décalage du fuseau horaire de l'utilisateur, vous êtes bon.

Ne traite pas des règles d'heure d'été, cependant ...

Roger Lipscombe
la source
15

Dans le cas (rare admis) où une heure de données locale est souhaitée (par exemple, je stocke l'heure locale dans l'une de mes bases de données, car tout ce qui m'importe, c'est l'heure de la journée et je ne garde pas trace de l'endroit où j'étais en terme de fuseaux horaires ...), vous pouvez définir la colonne comme

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

La partie% Y-% m-% dT% H:% M est bien entendu optionnelle; c'est ainsi que j'aime que mon temps soit stocké. [De plus, si mon impression est correcte, il n'y a pas de type de données "DATETIME" dans sqlite, donc peu importe si TEXT ou DATETIME est utilisé comme type de données dans la déclaration de colonne.]

polyglotte
la source
sqlite localtime peut être moins important dans les horodatages et dans les applications où l'utilisateur final n'utilise pas les données directement via un outil BI. Cependant, l'heure locale est ce que vous devez utiliser pour stocker toutes les dates spécifiques à l'application, telles que la date de naissance.
NoChance
9

Lorsqu'une colonne est définie avec " NOT NULL DEFAULT CURRENT_TIMESTAMP," les enregistrements insérés seront toujours définis avec l'heure UTC / GMT.

Voici ce que j'ai fait pour éviter d'avoir à inclure l'heure dans mes instructions 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

Testez pour voir si cela fonctionne ...

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

J'espère que cela pourra aider.

Boursiers Donal
la source
1
Est-ce différent de la réponse fournie par l'utilisateur hoju, CREATE TABLE peu importe (.... horodatage DATE DEFAULT (datetime ('now', 'localtime')),.) ;?
NoChance
8
SELECT datetime('now', 'localtime');
liquide
la source
7

SELECT datetime(CURRENT_TIMESTAMP, 'localtime')

Jens A. Koch
la source
4

Vous pouvez également simplement convertir la colonne de temps en un horodatage en utilisant strftime ():

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

Vous donne:

1454521888

La colonne de table 'timestamp' peut être un champ de texte même, en utilisant current_timestampcomme DEFAULT.

Sans délai:

SELECT timestamp FROM ... ;

Vous donne:

03/02/2016 17:51:28

danger89
la source
3

Je pense que cela pourrait aider.

SELECT datetime(strftime('%s','now'), 'unixepoch', 'localtime');
Alex
la source
pour unxitime; SELECT strftime ('% s', 'maintenant', 'heure locale');
PodTech.io
2

Time ( 'now', 'localtime' )et Date ( 'now', 'localtime' )fonctionne.

julien
la source