1

MongoDB から MySQL にデータ ダンプをインポートする小さな Django プロジェクトがあります。これらの Mongo ダンプ内には、エポック時間で保存された日付があります。タイムゾーンに関係なくエポック時間が同じであると予想しますが、私が見ているのは、Django TIME_ZONE設定が MySQL で作成されたデータに影響を与えることです。

MySQL UNIX_TIMESTAMP関数を使用してデータベース出力をテストしています。(ミリ秒を含む)のエポックで日付を挿入すると1371131402880、タイムゾーンが に設定され'America/New_York'、UNIX_TIMESTAMP は1371131402、ミリ秒を除いた同じエポック時間である を返します。ただし、タイムゾーンをに設定する'America/Chicago'と、1371127802.

datetimeこれは、エポック時間を Pythonオブジェクトに変換する私のコードです。

from datetime import datetime
from django.utils.timezone import utc

secs = float(epochtime) / 1000.0
dt = datetime.fromtimestamp(secs)

datetimeオブジェクトに明示的なタイムゾーンを設定して問題を解決しようとしましたが、

# epoch time is in UTC by default
dt = dt.replace(tzinfo=utc)

コードの PythonFiddle

この Python コードを単独でテストしたところ、期待どおりの結果が得られました。ただし、Django モデルのDateTimeFieldフィールドを介してこれらのオブジェクトを MySQL に挿入すると、正しい結果が得られません。

これが私のMySQLクエリです。

SELECT id, `date`, UNIX_TIMESTAMP(`date`) FROM table

このクエリの結果の unix タイムスタンプ列を MongoDB JSON ダンプと比較して、エポックが一致するかどうかを確認することで、これをテストします。

ここで何が起こっているのですか?タイムゾーンがエポック時間に影響を与えるのはなぜですか?

参考までに、Django 1.5.1 と MySQL-python 1.2.4 を使用しています。また、Django USE_TZフラグを に設定していtrueます。

4

1 に答える 1

1

私は Python や Django の第一人者ではないので、誰かが私よりもうまく答えられるかもしれません。しかし、私はとにかくそれを推測します。

あなたはそれをDjangoに保存していると言いました.Djangoはあなたが参照したドキュメントDateTimeFieldによると、それをPythonとして保存しています.datetime

のドキュメントをdatetime見ると、重要なのは「素朴な」値と「認識している」値の違いを理解することだと思います。

そして、さらに調査したところ、この優れた参考文献に出会いました。2 番目のセクション「単純で認識可能な datetime オブジェクト」を必ずお読みください。これにより、Django がこれをどの程度制御しているかが少しわかります。基本的に、 を設定するUSE_TZ = trueことで、Django にナイーブな日時ではなく、認識可能な日時を使用するように求めます。

それで、私はあなたの質問を振り返りました。あなたは次のことをしていると言いました:

dt = datetime.fromtimestamp(secs)
dt = dt.replace(tzinfo=utc)

fromtimestamp関数のドキュメントを見ると、次のテキストが見つかりました。

オプションの引数tzが指定されているNoneか指定されていない場合、timestampはプラットフォームのローカルの日付と時刻に変換され、返さdatetimeれるオブジェクトはナイーブです。

だから私はあなたがこれを行うことができると思います:

dt = datetime.fromtimestamp(secs, tz=utc)

次に、その関数のすぐ下に、ドキュメントがutcfromtimestamp関数を表示するので、次のようにする必要があります。

dt = datetime.utcfromtimestamp(secs)

これらが同等かどうかを知るにはPythonについて十分に知りませんが、どちらかが違いを生むかどうかを試してみることができます.

うまくいけば、これらの1つが違いを生むでしょう。そうでない場合は、お知らせください。私は JavaScript と .Net の日付/時刻に精通していますが、これらのニュアンスが Python などの他のプラットフォームでどのように異なるのか常に興味があります。

アップデート

質問の MySQL 部分については、この fiddleをご覧ください。

CREATE TABLE foo (`date` DATETIME);
INSERT INTO foo (`date`) VALUES (FROM_UNIXTIME(1371131402));

SET TIME_ZONE="+00:00";
select `date`, UNIX_TIMESTAMP(`date`) from foo;

SET TIME_ZONE="+01:00";
select `date`, UNIX_TIMESTAMP(`date`) from foo;

結果:

DATE                           UNIX_TIMESTAMP(`DATE`)
June, 13 2013 13:50:02+0000    1371131402
June, 13 2013 13:50:02+0000    1371127802

関数の動作UNIX_TIMESTAMPは実際に MySQL のTIME_ZONE設定の影響を受けるようです。ドキュメントに記載されているので、それほど驚くことではありません。驚くべきことはdatetime、設定に関係なく、 の文字列出力が同じ UTC 値を持つことです。

これが私が起こっていると思うことです。UNIX_TIMESTAMP関数のドキュメントでは、次のように述べています。

dateは、DATE文字列、DATETIME文字列、a 、またはorTIMESTAMPの形式の数値です。YYMMDDYYYYMMDD

それが a である可能性があるとは言っていないことに注意してくださいDATETIME- それはDATETIME stringである可能性があると言っています。したがって、実際の値は、関数に渡される前に暗黙的に文字列に変換されると思います。

それでは、明示的に変換するこの更新されたフィドルを見てください。

SET TIME_ZONE="+00:00";
select `date`, convert(`date`, char), UNIX_TIMESTAMP(convert(`date`, char)) from foo;

SET TIME_ZONE="+01:00";
select `date`, convert(`date`, char), UNIX_TIMESTAMP(convert(`date`, char)) from foo;

結果:

DATE                           CONVERT(`DATE`, CHAR)  UNIX_TIMESTAMP(CONVERT(`DATE`, CHAR))
June, 13 2013 13:50:02+0000    2013-06-13 13:50:02    1371131402
June, 13 2013 13:50:02+0000    2013-06-13 13:50:02    1371127802

文字データに変換すると、オフセットが取り除かれていることがわかります。UNIX_TIMESTAMPもちろん、この値を入力として受け取ると、ローカル タイム ゾーンの設定が想定されるため、別の UTC タイムスタンプが取得されることは理にかなっています。

これが役立つかどうかはわかりません。Django が読み取りと書き込みの両方で MySQL を呼び出す方法を正確に掘り下げる必要があります。実際にUNIX_TIMESTAMP機能を使用していますか?それとも、それはあなたがテストで行ったことですか?

于 2013-06-15T23:05:24.803 に答える