Sqlite:CURRENT_TIMESTAMPはマシンのタイムゾーンではなくGMTです


118

次の列定義を持つsqlite(v3)テーブルがあります。

"timestamp" DATETIME DEFAULT CURRENT_TIMESTAMP

このデータベースが存在するサーバーは、CSTタイムゾーンにあります。タイムスタンプ列を含めずにテーブルに挿入すると、sqliteはそのフィールドにCSTではなくGMTの現在のタイムスタンプを自動的に入力します。

保存されたタイムスタンプを強制的にCSTにするために、挿入ステートメントを変更する方法はありますか?一方、(たとえば、データベースが別のタイムゾーンに移動された場合に備えて)GMTで保存することをお勧めします。そのため、選択したSQLを変更して、保存されているタイムスタンプをCSTに変換する方法があります。テーブルからそれを抽出しますか?


24
タイムスタンプをUTCに格納することは、ベストプラクティスと見なされます。それらを提示するときに現地時間に変換ます。
csl 2015年

2
POSIXは、UTCとしてタイムスタンプを定義:stackoverflow.com/a/34107910/895245
チロSantilli郝海东冠状病六四事件法轮功

1
この種の問題が他のタイプのデータベースに直面しているかどうかは不明です。日本でデータベースを作成すれば、英国でデータを使用できると想像できます。
NoChance

回答:


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 2013

はい、それは私のためにも機能していません、私はZF2でsqliteを使用しています
Rohutech

@iconoclastは、これに気づいていて、実装が容易になる場合は危険ではありませんか?これがローカルタイムゾーンをデータベースに格納するためだけに必要なものであり、アプリケーションが他の方法を必要としないことがわかっている場合は、必要になります。
2016

1
@xFighter 私のアプリケーションが他の方法を必要とすることは決してないことを知っています ...あなたがそれを忘れるか、誰かがそれを使用するまで。
MKesper 2017年

16

原則として、データベースのタイムスタンプはGMTのままにして、ユーザーの(サーバーではなく)ローカルタイムスタンプに変換できる場合は、入出力のローカル時間との間でのみ変換する必要があります。

次のことができるといいですね。

SELECT DATETIME(col, 'PDT')

...太平洋夏時間のユーザーのタイムスタンプを出力します。残念ながら、それは機能しません。このSQLiteチュートリアルによるとただし、([その他の日付と時刻のコマンド]までスクロールして)、時間を要求し、同時にオフセット(時間単位)を適用できます。したがって、ユーザーのタイムゾーンオフセットがわかっている場合は問題ありません。

しかし、夏時間のルールは扱いません...


15

ローカルデータタイムが必要な(認められたまれな)ケース(たとえば、ローカル時間を自分のデータベースの1つに保存します。なぜなら、私が気にしているのは、その日の時間であり、どこにいたのかを追跡しないためです。タイムゾーンに関して...)、列を次のように定義できます

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

%Y-%m-%dT%H:%Mの部分はもちろんオプションです。自分の時間を保存するのが好きなのです。[また、私の印象が正しければ、sqliteに "DATETIME"データ型がないため、列宣言でデータ型としてTEXTとDATETIMEのどちらを使用しても問題ありません。]


sqlite localtimeは、タイムスタンプや、エンドユーザーがBIツールを介して直接データを使用しないアプリケーションではそれほど重要ではない場合があります。ただし、ローカルタイムは、誕生日などのすべてのアプリケーション固有の日付を格納するために使用する必要があるものです。
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とは異なりますか。
NoChance



4

strftime()を使用して、time列をタイムスタンプに変換することもできます。

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

あなたにあげる:

1454521888

'timestamp'テーブル列は、 current_timestamp as DEFAULT。

strftimeなし:

SELECT timestamp FROM ... ;

あなたにあげる:

2016-02-03 17:51:28




弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.