为什么Django时区设置会影响纪元时间?

时间:2013-06-15 19:52:45

标签: mysql django timezone epoch

我有一个小的Django项目,它将MongoDB中的数据转储导入MySQL。在这些Mongo转储中,日期存储在纪元时间。无论时区如何,我都希望纪元时间相同,但我看到的是Django TIME_ZONE设置对MySQL中创建的数据有影响。

我一直使用MySQL UNIX_TIMESTAMP函数测试我的数据库输出。如果我插入时间为1371131402880的日期(包括毫秒),我的时区设置为'America/New_York',UNIX_TIMESTAMP给我1371131402,这是相同的纪元时间,不包括毫秒。但是,如果我将时区设置为'America/Chicago',我会1371127802

这是我将纪元时间转换为Python datetime对象的代码,

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 for the code

我已经单独测试了这个Python代码,它给了我预期的结果。但是,在通过Django模型DateTimeField字段将这些对象插入MySQL后,它没有给出正确的结果。

这是我的MySQL查询,

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

我通过将此查询结果中的unix timestamp列与MongoDB JSON转储进行比较来测试,以查看epoch是否匹配。

这到底发生了什么?为什么时区对纪元时代有影响?

仅供参考,我使用的是Django 1.5.1和MySQL-python 1.2.4。我还将Django USE_TZ标志设置为true

1 个答案:

答案 0 :(得分:1)

我不是python或Django大师,所以也许有人可以比我更好地回答。但无论如何我会猜测它。

你说你把它存放在Django DateTimeField中,根据the documents you referenced,它将它存储为Python datetime

关注the docs for datetime,我认为关键是要理解“天真”和“意识”价值之间的区别。

然后进一步研究,我遇到了this excellent reference。请务必阅读第二部分“天真并了解日期时间对象”。这给出了Django控制其中多少内容的一些背景。基本上,通过设置USE_TZ = true,您要求Django使用识别日期时间而不是天真

然后我回头看了你的问题。你说你正在做以下事情:

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

查看fromtimestamp函数文档,我发现了这段文字:

  

如果可选参数tzNone或未指定,则timestamp将转换为平台的本地日期和时间,并且返回的datetime对象是天真的。< / p>

所以我认为你可以这样做:

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

然后,再次,在该函数下方,文档显示utcfromtimestamp函数,所以也许应该是:

dt = datetime.utcfromtimestamp(secs)

我不太了解python,知道这些是否相同,但你可以试着看看是否有所作为。

希望其中一个会有所作为。如果没有,请告诉我。我非常熟悉JavaScript和.Net中的日期/时间,但我总是对这些细微差别在其他平台(例如Python)中的表现方式感兴趣。

更新

关于问题的MySQL部分,请查看this 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字符串,TIMESTAMP或格式为YYMMDDYYYYMMDD的数字

请注意,它并不表示它可以是DATETIME - 它表示它可以是DATETIME 字符串 。所以我认为实际值在传递给函数之前被隐式转换为字符串。

现在看看明确转换的this updated fiddle

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函数?或者那就是你在测试中所做的那样?

相关问题