如何确保保存在数据库中的UTC日期等于Django中指定时区的午夜[重复]

Posted

技术标签:

【中文标题】如何确保保存在数据库中的UTC日期等于Django中指定时区的午夜[重复]【英文标题】:how to make sure that the UTC date saved in the database is equivalent to midnight in the specified timezone in Django [duplicate] 【发布时间】:2016-03-21 09:43:39 【问题描述】:

我想将数据库中的日期时间保存为特定用户的午夜。我将时区保存在我的用户对象上。但是,数据库一直将其保存为 UTC 的午夜。下面是我正在使用的代码。

tz_obj = pytz.timezone(user.timezone)
start_date = tz_obj.normalize(date_obj.replace(day=1, hour=0, minute=0, second=0, microsecond=0))
end_date = tz_obj.normalize(date_obj.replace(day=calendar.monthrange(date_obj.year, date_obj.month)[1], hour=23, minute=59,
                                    second=59, microsecond=99999))
obj = MyObject.objects.create(start=start_date, end=end_date)

谁能告诉我如何确保保存在数据库中的 UTC 日期等于指定时区的午夜。

更新 每个用户可能有不同的时区,因此在设置文件中设置时区并不能解决此问题。

【问题讨论】:

@DhiaTN:每个用户可能有不同的时区。您提供的答案没有帮助。我并不是要 +1 你的评论。 你的问题不够清楚,你更新了真是太好了:) 对不起。以为我做了显示时区保存在用户对象上。 这里的三个答案都是错误的。没关系。对副本的公认答案多年来也一直是错误的(现在它的错误更少了——它在更多情况下有效)。如果您需要正确的结果(根据 tz 数据库)或在代码无法获得结果时大声失败,请使用我的答案。 【参考方案1】:

注意:在 cmets 中,这种方法是不正确的。我们需要在用户的时区中获取date 对象,如重复问题中的答案。

因此,我们需要:datetime.now(tz).date(),而不是 date.today()


如果我的问题正确,您想将午夜存储在假设时区 +5:30 中,就像 UTC 中的 18:30 一样?如果是这种情况,您可以这样做:

>>> from datetime import date, time, datetime
>>> naive_midnight = datetime.combine(date.today(), time())
>>> tz = pytz.timezone('Asia/Kolkata')
>>>
>>> # Attach local timezone to above naive datetime object
>>> midnight_user_timezone = tz.localize(naive_midnight)
>>> print midnigth_user_timezone
2015-12-15 00:00:00+05:30
>>>
>>> # Convert to UTC
>>> midnight_to_utc = midnight_user_timezone.astimezone(pytz.UTC)
>>> print midnigth_to_utc
2015-12-14 18:30:00+00:00

【讨论】:

这是有效的。最后一步不是必需的,因为 Django 默认保存为 UTC。 @Dan:这是错误的,除非您的服务器的本地时区是亚洲/加尔各答,否则它无法工作。您服务器的时区应该是无关紧要的,并且不能在所有情况下都等于user.timezone(用户可能使用不同的时区)。 @J.F.Sebastian 我不明白。你能解释一下这种方法有什么问题吗?那太好了:) 您了解本地日期 (date.today()) 可能与 user.timezone (datetime.now(tz).date()) 中的日期不同吗?阅读我对重复问题的回答 @J.F.Sebastian 哦,是的。这可能会产生 1 天的差异。知道了。谢谢:)【参考方案2】:

Django 有一个名为 make_aware 的函数,用于将时区原始日期时间对象转换为时区感知日期时间对象。

aware_date_obj = make_aware(date_obj, user.timezone)

由于 datetime 对象已经链接到正确的时区,您只需在 aware_date_obj 上使用您的 .replace(day=1, hour=0, minute=0, second=0, microsecond=0),您就会在指定的时区获得年初。

如果 datetime 对象已经识别时区但不在正确的时区,您可以使用astimezone 将其转换为正确的时区:

date_obj.astimezone(user.timezone)

然后您可以再次使用.replace 函数。

最后,当 Django 在数据库中存储 datetime 对象时,时区信息会丢失。时间点仍然是正确的,但在从数据库加载后会链接到默认的 django 时区。然后,您将不得不再次使用 astimezone 函数将其链接到正确的时区。

【讨论】:

.replace(day=1,hour=0) on timezone-aware datetime object 可能跨越 DST 边界(结果可能有错误的 utc 偏移量)。阅读我对重复问题的回答,了解如何正确获得午夜。

以上是关于如何确保保存在数据库中的UTC日期等于Django中指定时区的午夜[重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何在特定时区转换 DateTime?

如何在特定时区转换 DateTime?

Utc 日期保存为 Sqlite 中的本地日期

关于在SQL Server中使用UTC时间保存当前日期的问题

如何仅使用标准库将 UTC 日期时间转换为本地日期时间?

如何在 django 中自定义数据库连接设置的时区?