1

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

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

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

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 大师,所以也许有人可以比我回答得更好。但无论如何我都会猜测一下。

您说您将它存储在 DjangoDateTimeField中,根据您引用的文档,它会将其存储为 Python datetime

查看文档datetime,我认为关键是理解“天真”和“有意识”值之间的区别。

然后进一步研究,我遇到了这个优秀的参考资料。请务必阅读第二部分“朴素且有意识的日期时间对象”。这为 Django 控制了多少提供了一些背景信息。基本上,通过设置USE_TZ = true,您要求 Django 使用有意识的日期时间而不是天真的日期时间。

所以我回头看了你的问题。您说您正在执行以下操作:

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

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

如果指定或未指定可选参数,则将其转换为平台的本地日期和时间,并且返回的tz对象是朴素的。Nonetimestampdatetime

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

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

再说一次,在该函数的正下方,文档显示utcfromtimestamp函数,所以它可能应该是:

dt = datetime.utcfromtimestamp(secs)

我对 python 的了解还不够,无法知道它们是否等效,但是您可以尝试看看两者是否有所不同。

希望其中之一会有所作为。如果没有,请告诉我。我非常熟悉 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函数的行为确实受到 MySQLTIME_ZONE设置的影响。这并不奇怪,因为它在文档中。令人惊讶的是,datetime无论设置如何, 的字符串输出都具有相同的 UTC 值。

这就是我认为正在发生的事情。在该UNIX_TIMESTAMP函数的文档中,它说:

date可以是DATE字符串、DATETIME字符串、aTIMESTAMP或格式为YYMMDDor的数字YYYYMMDD

请注意,它并没有说它可以是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 回答