SQLite:CURRENT_TIMESTAMP以格林尼治标准时间表示,而不是计算机的时区


118

我有一个带有此列定义的sqlite(v3)表:

"timestamp" DATETIME DEFAULT CURRENT_TIMESTAMP

该数据库所在的服务器位于CST时区。当我在不包括timestamp列的情况下插入表时,sqlite会自动以GMT(而不是CST)中的当前时间戳填充该字段。

有没有办法修改我的插入语句,以强制存储的时间戳记在CST中?另一方面,最好将其存储在GMT中(例如,以防数据库移动到其他时区),所以有一种方法可以修改我选择的SQL,以便在我将存储的时间戳转换为CST时从表中提取出来?


24
在UTC中存储时间戳被认为是最佳做法。呈现其转换为当地时间。
csl


1
不知道这种麻烦是否会面对其他类型的数据库。您以为如果在日本创建数据库,就可以在英国使用数据!
NoChance

Answers:


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
这确实存在不能跨时区转移的问题,但是,不是吗?
Vadim Peretokin

是的,它对我也不起作用,我在ZF2中使用sqlite
Rohutech

@iconoclast如果您意识到这一点并且如果它使您的实现更容易,应该不是很危险吗?如果这是我只需要将本地时区存储到数据库中并且我知道我的应用程序永远不需要其他方式,那么我会。
阿哈德

1
@xFighter 我知道我的应用程序再也不需要其他方式了 ...直到您忘记它或其他人正在使用它。
MKesper '17

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作为数据类型并不重要。


在最终用户不直接通过BI工具使用数据的时间戳和应用程序中,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

希望有帮助。


1
这是否与hoju用户提供的答案不同:CREATE TABLE what(.... timestamp DATE DEFAULT(datetime('now','localtime')),。);?
NoChance



4

您也可以使用strftime()将time列转换为时间戳:

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

给你:

1454521888

使用current_timestampas DEFAULT ,“时间戳”表列甚至可以是文本字段。

没有strftime:

SELECT timestamp FROM ... ;

给你:

2016-02-03 17:51:28


3

我认为这可能会有所帮助。

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

不合时宜 SELECT strftime('%s','now','localtime');
PodTech.io


1

Time ( 'now', 'localtime' )和日期( 'now', 'localtime' )有效。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.