Django 在将其保存到数据库时是否会破坏时区感知 DateTimeField?
Is Django corrupting timezone-aware DateTimeField when saving it to the Database?
我有一个描述的 Django 模型
我创建并保存了这个模型的实例:
>>> from django.db.models import Max, F, Func
>>> from django.conf import settings
>>> import pytz, datetime
>>> from myapp.models import myModel
>>> myModel.objects.all().delete()
>>> myModel.objects.create(
my_date=datetime.datetime(2037,4,2,15,18,17,tzinfo=pytz.UTC),
my_string="asda"
)
<myModel: myModel object>
然后我尝试检索我刚刚插入的实例,但我得到了本机格式的 DateTimeField,并且在应用 UNIX_TIMESTAMP
:
之后
>>> x = myModel.objects.values('my_string').aggregate(
max1=Max('my_date'),
max2=Max(Func(F('my_date'), function='UNIX_TIMESTAMP'))
)
>>> x
{
'max2': Decimal('2122848857.000000'),
'max1': datetime.datetime(2037, 4, 8, 20, 14, 17, tzinfo=<UTC>)
}
>>> datetime.datetime.utcfromtimestamp(x["max2"])
datetime.datetime(2037, 4, 9, 0, 14, 17)
>>> pytz.timezone(settings.TIME_ZONE)
<DstTzInfo 'America/New_York' LMT-1 day, 19:04:00 STD>
>>>
如果您 convert 2122848857
回到日期时间,您会得到 2037-04-09T00:14:17+00:00
。这比我实际插入的时间多了 4 个小时。为什么?如何纠正这种看似腐败的现象?我机器的时区是 EDT,比 UTC 晚 4 小时。但这仍然不能解释为什么 Django 保存这个 UTC 时间就好像它在我当地的时区一样。
import pytz, datetime
from django.db.models import Max, F, Func
from django.conf import settings
from myapp.models import myModel
local_tz = pytz.timezone(settings.TIME_ZONE)
local_datetime = local_tz.localize(datetime.datetime(2037, 4, 8, 20, 14, 17), is_dst=None)
utc_datetime = local_datetime.astimezone(pytz.UTC)
# datetime.datetime(2037, 4, 9, 0, 14, 17, tzinfo=<UTC>)
MyModel.objects.create(my_date=utc_datetime)
x = MyModel.objects.aggregate(max1=Max('my_date'),max2=Max(Func(F('my_date'), function='UNIX_TIMESTAMP')))
pytz.UTC.localize(datetime.datetime.fromtimestamp(x['max2'])).astimezone(local_tz) == x['max1'].astimezone(local_tz)
datetime
和 timestamp
之间的主要区别在于 timestamp
将使用当前的 mysql time_zone
设置自动将值存储为 UTC, datetime
将在插入和检索记录时忽略 time_zone
设置。
您正在使用 datetime
字段,但是您还在对该字段使用 mysql UNIX_TIMESTAMP
函数。当您这样做时,docs 解释服务器根据 time_zone
设置将该值解释为 local 时间值。这是转换差异的来源。
你有两个选择。
- 确保
time_zone
会话变量在 运行 您的查询之前设置为 UTC。
- 将值存储到
timestamp
字段而不是 datetime
字段。
是的。部分数据被丢弃。
Django DateTime 字段将数据存储在缺少时区信息的数据库 DateTime 存储中,因此在存储之前删除该信息。
这就是磨 the manual 说:
Note that if you set this to point to a DateTimeField, only the date portion of the > field will be considered. Besides, when USE_TZ is True, the check will be performed > in the current time zone at the time the object gets saved.
存储完整日期时间日期的正确方法是使用 DateTimeOffset 字段 - 可以在 MS-Sql 和其他文件中找到。但是这个不支持(yet?)
我有一个描述的 Django 模型
我创建并保存了这个模型的实例:
>>> from django.db.models import Max, F, Func
>>> from django.conf import settings
>>> import pytz, datetime
>>> from myapp.models import myModel
>>> myModel.objects.all().delete()
>>> myModel.objects.create(
my_date=datetime.datetime(2037,4,2,15,18,17,tzinfo=pytz.UTC),
my_string="asda"
)
<myModel: myModel object>
然后我尝试检索我刚刚插入的实例,但我得到了本机格式的 DateTimeField,并且在应用 UNIX_TIMESTAMP
:
>>> x = myModel.objects.values('my_string').aggregate(
max1=Max('my_date'),
max2=Max(Func(F('my_date'), function='UNIX_TIMESTAMP'))
)
>>> x
{
'max2': Decimal('2122848857.000000'),
'max1': datetime.datetime(2037, 4, 8, 20, 14, 17, tzinfo=<UTC>)
}
>>> datetime.datetime.utcfromtimestamp(x["max2"])
datetime.datetime(2037, 4, 9, 0, 14, 17)
>>> pytz.timezone(settings.TIME_ZONE)
<DstTzInfo 'America/New_York' LMT-1 day, 19:04:00 STD>
>>>
如果您 convert 2122848857
回到日期时间,您会得到 2037-04-09T00:14:17+00:00
。这比我实际插入的时间多了 4 个小时。为什么?如何纠正这种看似腐败的现象?我机器的时区是 EDT,比 UTC 晚 4 小时。但这仍然不能解释为什么 Django 保存这个 UTC 时间就好像它在我当地的时区一样。
import pytz, datetime
from django.db.models import Max, F, Func
from django.conf import settings
from myapp.models import myModel
local_tz = pytz.timezone(settings.TIME_ZONE)
local_datetime = local_tz.localize(datetime.datetime(2037, 4, 8, 20, 14, 17), is_dst=None)
utc_datetime = local_datetime.astimezone(pytz.UTC)
# datetime.datetime(2037, 4, 9, 0, 14, 17, tzinfo=<UTC>)
MyModel.objects.create(my_date=utc_datetime)
x = MyModel.objects.aggregate(max1=Max('my_date'),max2=Max(Func(F('my_date'), function='UNIX_TIMESTAMP')))
pytz.UTC.localize(datetime.datetime.fromtimestamp(x['max2'])).astimezone(local_tz) == x['max1'].astimezone(local_tz)
datetime
和 timestamp
之间的主要区别在于 timestamp
将使用当前的 mysql time_zone
设置自动将值存储为 UTC, datetime
将在插入和检索记录时忽略 time_zone
设置。
您正在使用 datetime
字段,但是您还在对该字段使用 mysql UNIX_TIMESTAMP
函数。当您这样做时,docs 解释服务器根据 time_zone
设置将该值解释为 local 时间值。这是转换差异的来源。
你有两个选择。
- 确保
time_zone
会话变量在 运行 您的查询之前设置为 UTC。 - 将值存储到
timestamp
字段而不是datetime
字段。
是的。部分数据被丢弃。
Django DateTime 字段将数据存储在缺少时区信息的数据库 DateTime 存储中,因此在存储之前删除该信息。
这就是磨 the manual 说:
Note that if you set this to point to a DateTimeField, only the date portion of the > field will be considered. Besides, when USE_TZ is True, the check will be performed > in the current time zone at the time the object gets saved.
存储完整日期时间日期的正确方法是使用 DateTimeOffset 字段 - 可以在 MS-Sql 和其他文件中找到。但是这个不支持(yet?)