关于sql:Sqlite:CURRENT_TIMESTAMP是GMT,而不是机器的时区

Sqlite: CURRENT_TIMESTAMP is in GMT, not the timezone of the machine

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

1
"timestamp" DATETIME DEFAULT CURRENT_TIMESTAMP

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

是否有方法修改insert语句以强制存储的时间戳位于cst中?另一方面,最好将其存储在gmt中(例如,如果数据库移动到其他时区),那么在从表中提取时间戳时,是否可以修改select sql以将存储的时间戳转换为cst?


我在sqlite文档(https://www.sqlite.org/lang_datefunc.html)中找到以下文本:

Compute the date and time given a unix
timestamp 1092941466, and compensate
for your local timezone.

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

这看起来不符合我的需要,所以我尝试了稍微改变一下"datetime"函数,最后得出结论:

1
SELECT datetime(TIMESTAMP, 'localtime')

这似乎可行——这是转换时区的正确方法,还是有更好的方法?


只需使用本地时间作为默认值:

1
2
3
4
5
CREATE TABLE whatever(
     ....
     TIMESTAMP DATE DEFAULT (datetime('now','localtime')),
     ...
);


通常,您应该将时间戳保留在数据库中的GMT格式,并且只有在输入/输出时才能将它们转换为/从本地时间转换为用户的(而不是服务器的)本地时间戳。

如果你能做到以下几点就好了:

1
SELECT DATETIME(col, 'PDT')

…在太平洋夏令时为用户输出时间戳。不幸的是,这行不通。但是,根据这个sqlite教程(向下滚动到"其他日期和时间命令"),您可以请求时间,然后同时应用偏移量(以小时为单位)。所以,如果你知道用户的时区偏移量,你就很好了。

但不涉及日光节约规则…


在需要本地数据时间(例如,我将本地时间存储在我的数据库中,因为我只关心一天中的时间是什么,我不跟踪我在时区中的位置…)的情况下,您可以将该列定义为

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

%y-%m-%dt%h:%m部分当然是可选的;这正是我希望存储时间的方式。[另外,如果我的印象是正确的,则sqlite中没有"datetime"数据类型,因此在列声明中是否将text或datetime用作数据类型并不重要。]


当列定义为"EDOCX1"(0)时,插入的记录将始终使用UTC/GMT时间进行设置。

以下是我为避免在insert/update语句中包含时间而做的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
--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

测试看它是否工作…

1
2
3
4
5
6
7
8
9
10
11
12
--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
SELECT datetime('now', 'localtime');


SELECT datetime(CURRENT_TIMESTAMP, 'localtime')


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

1
SELECT strftime('%s', TIMESTAMP) AS TIMESTAMP FROM ... ;

给你:

1454521888

"timestamp"表列甚至可以是文本字段,使用current_timestamp作为默认值。

无strftime:

1
SELECT TIMESTAMP FROM ... ;

给你:

2016-02-03 17:51:28


我想这可能有帮助。

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


当前时间,在机器的时区中:

1
SELECT TIME(TIME(), 'localtime');

根据http://www.sqlite.org/lang_datefunc.html


Time ( 'now', 'localtime' )和日期( 'now', 'localtime' )工程。