Sqlite: CURRENT_TIMESTAMP dalam GMT, bukan zona waktu mesin

119

Saya memiliki tabel sqlite (v3) dengan definisi kolom ini:

"timestamp" DATETIME DEFAULT CURRENT_TIMESTAMP

Server tempat database ini berada dalam zona waktu CST. Ketika saya memasukkan ke dalam tabel saya tanpa menyertakan kolom cap waktu, sqlite secara otomatis mengisi bidang itu dengan cap waktu saat ini dalam GMT, bukan CST.

Apakah ada cara untuk mengubah pernyataan penyisipan saya untuk memaksa stempel waktu yang disimpan berada di CST? Di sisi lain, mungkin lebih baik menyimpannya dalam GMT (jika database dipindahkan ke zona waktu yang berbeda, misalnya), jadi apakah ada cara saya dapat memodifikasi SQL pilihan saya untuk mengonversi stempel waktu yang disimpan ke CST saat saya mengekstraknya dari tabel?

BrianH
sumber
25
Menyimpan stempel waktu dalam UTC dianggap sebagai praktik terbaik. Ubah ke waktu lokal saat mempresentasikannya .
csl
2
POSIX mendefinisikan cap waktu sebagai UTC: stackoverflow.com/a/34107910/895245
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
Tidak yakin apakah masalah seperti ini menghadapi jenis database lain. Anda akan membayangkan bahwa jika Anda membuat database di Jepang, Anda dapat menggunakan data di Inggris!
NoChance

Jawaban:

146

Saya menemukan di dokumentasi sqlite ( https://www.sqlite.org/lang_datefunc.html ) teks ini:

Hitung tanggal dan waktu dengan stempel waktu unix 1092941466, dan kompensasi untuk zona waktu lokal Anda.

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

Sepertinya itu tidak sesuai dengan kebutuhan saya, jadi saya mencoba mengubah sedikit fungsi "waktu", dan berakhir dengan ini:

select datetime(timestamp, 'localtime')

Tampaknya berhasil - apakah itu cara yang benar untuk mengubah zona waktu Anda, atau adakah cara yang lebih baik untuk melakukannya?

BrianH
sumber
65

cukup gunakan waktu lokal sebagai default:

CREATE TABLE whatever(
     ....
     timestamp DATE DEFAULT (datetime('now','localtime')),
     ...
);
hoju
sumber
5
Ini memang memiliki masalah karena tidak dapat ditransfer antar zona waktu, bukan?
Vadim Peretokin
ya, ini juga tidak berfungsi untuk saya, saya menggunakan sqlite di ZF2
Rohutech
@iconoclast seharusnya tidak berbahaya jika Anda menyadarinya dan jika membuat implementasi Anda lebih mudah, bukan? jika ini yang saya perlukan hanya untuk menyimpan zona waktu lokal ke dalam database dan saya tahu aplikasi saya tidak akan membutuhkan cara lain maka saya akan melakukannya.
Ahad
1
@xFighter Saya tahu aplikasi saya tidak akan membutuhkan cara lain ... Sampai Anda melupakannya atau orang lain sedang menggunakannya.
MKesper
16

Biasanya, Anda harus membiarkan stempel waktu dalam database dalam GMT, dan hanya mengonversinya ke / dari waktu lokal pada input / output, saat Anda dapat mengonversinya menjadi stempel waktu lokal pengguna (bukan server).

Alangkah baiknya jika Anda bisa melakukan hal berikut:

SELECT DATETIME(col, 'PDT')

... untuk mengeluarkan stempel waktu pengguna pada Waktu Musim Panas Pasifik. Sayangnya, itu tidak berhasil. Menurut tutorial SQLite ini , bagaimanapun (gulir ke bawah ke "Perintah Tanggal dan Waktu Lainnya"), Anda dapat menanyakan waktu, dan kemudian menerapkan offset (dalam jam) pada saat yang sama. Jadi, jika Anda mengetahui perbedaan zona waktu pengguna, Anda bagus.

Tidak berurusan dengan aturan penghematan siang hari, meskipun ...

Roger Lipscombe
sumber
15

Dalam kasus (jarang diakui) bahwa datatime lokal dibutuhkan (saya, misalnya, menyimpan waktu lokal di salah satu database saya karena yang saya pedulikan adalah jam berapa hari itu dan saya tidak melacak di mana saya berada dalam istilah zona waktu ...), Anda dapat menentukan kolom sebagai

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

Bagian% Y-% m-% dT% H:% M tentu saja opsional; hanya bagaimana saya ingin waktu saya disimpan. [Selain itu, jika kesan saya benar, tidak ada tipe data "DATETIME" di sqlite, jadi tidak masalah apakah TEXT atau DATETIME digunakan sebagai tipe data dalam deklarasi kolom.]

poliglot
sumber
sqlite localtime mungkin kurang penting dalam stempel waktu dan dalam aplikasi di mana pengguna akhir tidak menggunakan data secara langsung melalui alat BI. Namun, waktu lokal adalah apa yang perlu Anda gunakan untuk menyimpan semua tanggal spesifik aplikasi seperti tanggal lahir.
NoChance
9

Saat memiliki kolom yang ditentukan dengan " NOT NULL DEFAULT CURRENT_TIMESTAMP," rekaman yang dimasukkan akan selalu disetel dengan waktu UTC / GMT.

Inilah yang saya lakukan untuk menghindari keharusan memasukkan waktu dalam pernyataan INSERT / UPDATE saya:

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

Uji untuk melihat apakah itu berhasil ...

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

Semoga membantu.

Donal Fellows
sumber
1
Apakah ini berbeda dengan jawaban yang diberikan oleh pengguna hoju, CREATE TABLE apapun (.... timestamp DATE DEFAULT (datetime ('now', 'localtime')),.) ;?
NoChance
8
SELECT datetime('now', 'localtime');
mencair
sumber
7

SELECT datetime(CURRENT_TIMESTAMP, 'localtime')

Jens A. Koch
sumber
4

Anda juga dapat mengubah kolom waktu menjadi stempel waktu dengan menggunakan strftime ():

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

Memberi anda:

1454521888

Kolom tabel 'timestamp' bisa berupa kolom teks, menggunakan current_timestampas DEFAULT.

Tanpa strftime:

SELECT timestamp FROM ... ;

Memberi anda:

2016-02-03 17:51:28

bahaya89
sumber
3

Saya pikir ini mungkin membantu.

SELECT datetime(strftime('%s','now'), 'unixepoch', 'localtime');
Alex
sumber
untuk waktu luang; PILIH strftime ('% s', 'now', 'localtime');
PodTech.io
2

Time ( 'now', 'localtime' )dan Tanggal ( 'now', 'localtime' )bekerja.

Julian
sumber