それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

SQLiteのタイムゾーン

SQLiteでは、タイムゾーンは考慮されてないっぽい(2013-06-01調べ)

全ては文字列だと考えるといいかも。

保存した時の表記そのままで時間が返ってくる。

ただしCURRENT_TIMESTAMPはUTC

CURRENT_TIMESTAMP は 保存時にUTCで保存される

だから、取り出すときもUTCで出てくるので、表示スルときに、ローカル時刻として表示する必要がある。

取り出すときはlocaltime を使う。
sqlite> select datetime(datetime(),"localtime");
2013-09-12 03:28:23

sqlite> select datetime();
2013-09-11 18:28:31

確認してみた

SQLiteでテーブル作ったときに、よく注意する。

sqlite> .schema
CREATE TABLE price_log (
price int,
date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
data text
);


SQLiteのテーブルに入った、時刻はINT秒かTEXTで入っていて、UTC時刻で入ってる。
取り出すときにlocalize されてタイムゾーンが考慮されて出てくる・・ってことはあり得ないので
UTC時刻で出てきます

特に current_timestamp の時に注意する。
sqlite> select datetime(date) from stock_price_log limit 2;
2013-05-18 23:59:41
2013-08-19 00:23:10
sqlite> select datetime(date, "localtime") from stock_price_log limit 2;
2013-05-19 08:59:41
2013-05-19 09:23:10
sqlite>

このように、localtime で変換して表示する必要がある。でないと時間ずれる

current _timestampを使わない場合

タダの文字列なら

CREATE TABLE price_log (
price int not null ,
date int not null,

data text
);


データべースには、UTCでデータを放り込んで、取り出すときに、タイムゾーンに併せた表示に取り出すのが無難なので。
UTCで保存して 取り出すときに datetime関数でローカル時刻にすると良いと思います。


追記

タイムスタンプ(ユニックス・エポック)の経過時間(秒数)は扱うときに次のようにして扱う。

 SELECT  datetime(mtime,'unixepoch') FROM locates; ## => UTC 日付になる

冒頭にも述べたが、SQLiteは「基本的に文字列」*1なので、完全な数字で入れてたときはかえって不便です。

UTCのタイムスタンプをローカルの時間として直して(変換して)表示する

SELECT datetime(datetime(mtime,'unixepoch'),'localtime') FROM locates;


このように、unixepoch と localtime の2回の変換を挟みます。

繰り返しになりますが、ぶっちゃけめんどくさいのでJST(TZ=Asia/Tokyo)を前提とした「文字列」で突っ込んでおくのが無難です。

なので、何が入ってるは(タイムスタンプはJSTかどうか、日付文字列はUTCなのか)をキチンとメモを残しておくと良いのです。

もう一つ無難な回答で言えば、ISO8601形式で「文字列」として突っ込むことなんだが、

## Z をつけてUTCを明示
2013-05-19T00:23:10Z
## ±をつけて TZを明示
2013-05-19T09:23:10+9:00

一見すると良さそうにも見えるけど、date関数群がうまく解釈してくれないことがあり、プログラミング言語側で苦労を強いられることになったりする。

ISO8601 形式で保存したとしても strftime のフォーマットをcreate table など何処かにメモしておかなくていけない。だったらもう「JSTだよ」って書いたほうが楽だよね。って話な?

更に追記

SQLiteが進化してて `2013-05-19T09:23:10+9:00` のような文字列をちゃんとUNIX Epochに変換できるようになってた。だから ±をつけて保存したヤツが無難だ。

他の人に以下に伝えて残すか。

ミスの防止のために、UTC時刻だよ!って教えてあげないといけません。
コメントを使います。

SQLlite3のcreate table文はそのままコメントが残るので、UTC時刻のときはUTCと書くべき

CREATE TABLE stock_price_log (
price int not null , -- 価格
date int not null, -- UTC のタイムスタンプ。取り出すときにdatetime(date,"localtime") で。
data text
);


CREATE TABLE price_log (
price int not null , -- 価格
date int not null, -- JST時刻
data text
);

などと、明示的に書いたほうがいいですね。

ときどきUTC時刻に、JST時刻を入れて9時間早くなってて、タイムゾーンをオフにしないと動かないテーブルを見かけますが、ああいうの何考えてるんだろうな。

*1:正確にはstrptimeなどでGnu Dateと同等の自動変換