Sqlite: CURRENT_TIMESTAMP está en GMT, no en la zona horaria de la máquina

118

Tengo una tabla sqlite (v3) con esta definición de columna:

"timestamp" DATETIME DEFAULT CURRENT_TIMESTAMP

El servidor en el que vive esta base de datos se encuentra en la zona horaria CST. Cuando inserto en mi tabla sin incluir la columna de marca de tiempo, sqlite rellena automáticamente ese campo con la marca de tiempo actual en GMT, no en CST.

¿Hay alguna forma de modificar mi declaración de inserción para forzar que la marca de tiempo almacenada esté en CST? Por otro lado, probablemente sea mejor almacenarlo en GMT (en caso de que la base de datos se mueva a una zona horaria diferente, por ejemplo), entonces, ¿hay alguna manera de que pueda modificar mi SQL seleccionado para convertir la marca de tiempo almacenada a CST cuando extraerlo de la mesa?

BrianH
fuente
24
El almacenamiento de marcas de tiempo en UTC se considera una buena práctica. Conviértalo a la hora local al presentarlos .
CSL
2
POSIX define las marcas de tiempo como UTC: stackoverflow.com/a/34107910/895245
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
No estoy seguro de si este tipo de problemas enfrenta otros tipos de bases de datos. ¡Imaginaría que si crea una base de datos en Japón, podría usar los datos en el Reino Unido!
NoChance

Respuestas:

145

Encontré en la documentación de sqlite ( https://www.sqlite.org/lang_datefunc.html ) este texto:

Calcule la fecha y la hora con una marca de tiempo de Unix 1092941466 y compense su zona horaria local.

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

Eso no parecía encajar con mis necesidades, así que intenté cambiar un poco la función "datetime" y terminé con esto:

select datetime(timestamp, 'localtime')

Eso parece funcionar: ¿es esa la forma correcta de convertir para su zona horaria o hay una mejor manera de hacerlo?

BrianH
fuente
64

simplemente use la hora local como predeterminada:

CREATE TABLE whatever(
     ....
     timestamp DATE DEFAULT (datetime('now','localtime')),
     ...
);
hoju
fuente
5
Sin embargo, esto tiene el problema de no ser transferible entre zonas horarias, ¿no?
Vadim Peretokin
sí, lo es, tampoco me funciona, estoy usando sqlite en ZF2
Rohutech
@iconoclast no debería ser peligroso si está al tanto de esto y si facilita su implementación, ¿verdad? Si esto es lo que necesito solo para almacenar la zona horaria local en la base de datos y sé que mi aplicación nunca necesitará otra forma, entonces lo haré.
Ahad
1
@xFighter Sé que mi aplicación nunca necesitará de otra manera ... Hasta que te olvides de eso o alguien más la esté usando.
MKesper
16

Como regla general, debe dejar las marcas de tiempo en la base de datos en GMT y solo convertirlas a / desde la hora local en la entrada / salida, cuando puede convertirlas a la marca de tiempo local del usuario (no del servidor).

Sería bueno si pudiera hacer lo siguiente:

SELECT DATETIME(col, 'PDT')

... para generar la marca de tiempo de un usuario en la hora de verano del Pacífico. Desafortunadamente, eso no funciona. Sin embargo, de acuerdo con este tutorial de SQLite (desplácese hacia abajo hasta "Otros comandos de fecha y hora"), puede solicitar la hora y luego aplicar una compensación (en horas) al mismo tiempo. Entonces, si conoce la compensación de la zona horaria del usuario, está bien.

Sin embargo, no se ocupa de las reglas del horario de verano ...

Roger Lipscombe
fuente
15

En el caso (raro admitido) de que se desee una hora de datos local (yo, por ejemplo, guardo la hora local en una de mis bases de datos, ya que lo único que me importa es la hora del día y no hago un seguimiento de dónde estaba en términos de zonas horarias ...), puede definir la columna como

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

La parte% Y-% m-% dT% H:% M es, por supuesto, opcional; así es como me gusta que se almacene mi tiempo. [Además, si mi impresión es correcta, no hay un tipo de datos "DATETIME" en sqlite, por lo que realmente no importa si se usa TEXT o DATETIME como tipo de datos en la declaración de columna.]

polígloto
fuente
sqlite localtime puede ser menos importante en las marcas de tiempo y en aplicaciones donde el usuario final no usa los datos directamente a través de una herramienta de BI. Sin embargo, localtime es lo que necesita usar para almacenar todas las fechas específicas de la aplicación, como la fecha de nacimiento.
NoChance
9

Cuando se tiene una columna definida con " NOT NULL DEFAULT CURRENT_TIMESTAMP," los registros insertados siempre se configurarán con la hora UTC / GMT.

Esto es lo que hice para evitar tener que incluir la hora en mis declaraciones 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

Prueba para ver si 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 ayude.

Becarios Donal
fuente
1
¿Es esto diferente de la respuesta proporcionada por el usuario hoju, CREATE TABLE cualquiera (.... timestamp DATE DEFAULT (datetime ('ahora', 'localtime')),.) ;?
NoChance
7
SELECT datetime('now', 'localtime');
liquidar
fuente
6

SELECT datetime(CURRENT_TIMESTAMP, 'localtime')

Jens A. Koch
fuente
4

También puede convertir la columna de tiempo en una marca de tiempo usando strftime ():

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

Te dio:

1454521888

La columna de la tabla 'marca de tiempo' puede ser un campo de texto par, utilizando current_timestampcomo DEFAULT.

Sin strftime:

SELECT timestamp FROM ... ;

Te dio:

2016-02-03 17:51:28

peligro89
fuente
3

Creo que esto podría ayudar.

SELECT datetime(strftime('%s','now'), 'unixepoch', 'localtime');
Alex
fuente
para unxitime; SELECT strftime ('% s', 'ahora', 'localtime');
PodTech.io
1

Time ( 'now', 'localtime' )y la fecha ( 'now', 'localtime' )funciona.

Julian
fuente