问题描述
我有这段代码表现得很奇怪,并且提出了一个问题,我应该如何处理时区?因此,首先,我有一个根据用户发布的信息构建的datetime对象:
time_zone = request.POST.get("time_zone")
date_start = request.POST.get("date_start")
time_day = request.POST.get("time_day")
time_zone_obj = pytz.timezone("Etc/" + time_zone) # GMT + 2 in this example
date_start = datetime.strptime(date_start,"%d/%m/%Y")
date_start = date_start.replace(tzinfo=time_zone_obj)
time_day = datetime.strptime(time_day,"%I:%M %p")
date_start = date_start.replace(hour=time_day.hour,minute=time_day.minute)
...
event.date_start = date_start
event.save()
print("event.date_start.hour:%s" % event.date_start.hour)
print("event.date_start.tzinfo:%s" % event.date_start.tzinfo)
print("is_aware(event.date_start:%s)" % is_aware(event.date_start))
return redirect("event_detail",event_id=event.id)
这将打印event.date_start.hour:6
,event.date_start.tzinfo:Etc/GMT+2
和is_aware:True
。然后,在保存对象并打印小时后,立即进行调整,它重定向到event_detail
视图,非常简单:
def event_detail(request,event_id):
event = get_object_or_404(Event,id=event_id)
print("event.date_start.hour:%s" % event.date_start.hour)
print("event.date_start.tzinfo:%s" % event.date_start.tzinfo)
...
它会打印event.date_start.hour:8
和event.date_start.tzinfo:UTC
。 (它已用UTC替换了tz信息)我不明白为什么。我用清晰的tz_info保存对象。请注意,我是在保存对象后的一小时内打印出来的,然后在另一个视图中检索到它后的一小时。相差两个小时,这与用户选择的时区(GMT + 2)有关。为什么是这样?哪种方法是保存此数据的最佳方法?
用户在表单中提交“ 6:00 AM” +“ GMT + 2”,然后稍后当我想在事件详细信息html({{ event.date_start|date:"h:i A" }}
)中显示时间时,它显示“ 8:00 AM” “。
解决方法
我假设您正在使用PostgreSQL来保存时区感知时间戳。
重要的是要理解(与名称和流行的看法相反),PostgreSQL不会保存时区感知时间戳的时区。这只是一种告诉PostgreSQL该值不在本地时间,而是知道时区的方法。
然后PostgreSQL将其转换为UTC并进行存储。如果原始时区很重要,则需要将其单独存储。
有关该主题的更多信息:https://www.postgresqltutorial.com/postgresql-timestamp/
存储此数据的最佳方法是单独的一列(通常称为timezone
)。我使用https://pypi.org/project/django-timezone-field/
然后使用activate
时区(https://docs.djangoproject.com/en/3.1/ref/utils/#django.utils.timezone.activate)或使用localtime
(https://docs.djangoproject.com/en/3.1/ref/utils/#django.utils.timezone.localtime)实用程序功能。
根据Django docs,
“启用时区支持后,Django将DateTime信息存储在数据库中的UTC中。将数据存储在数据库中的UTC中仍然是一种好习惯。主要原因是夏令时(DST)。” >
因此可以按预期将UTC格式的DateTime保存在数据库中。
现在,继续您的要求。为了在用于保存的时区中显示时间,您需要在数据库中添加一列以存储时区信息。
在检索DateTime时,请使用存储在数据库中的tzinfo将其转换回所需的时区。
这是正确的做法。希望这可以帮助您更好地理解。