【问题标题】:Pytz - timezone activated yet getting wrong time. Am I missing something?Pytz - 时区已激活但时间错误。我错过了什么吗?
【发布时间】:2017-12-13 11:29:16
【问题描述】:

在我的主页上,我触发了以下视图定义

def initializeTimeZone(request):
    tzone = request.GET.get("tzone") # returns 'America/Los_Angeles'
    user_time_zone = request.session.get('user_time_zone', None)
    try:
        if user_time_zone is None:
            request.session['user_time_zone'] = tzone
            timezone.activate(pytz.timezone(tzone)) #--->is this correct ? 
            time = datetime.datetime.now().strftime(settings.DATE_TIME_OBJECT_FORMATTING) #--->Wrong
        return HttpResponse("OK")
    except Exception as ex:
        print >> sys.stderr, str(ex)

现在当我稍后做这样的事情时

time = datetime.datetime.now().strftime(settings.DATE_TIME_OBJECT_FORMATTING)

我弄错了日期 '2017-07-09 19:01:33'

关于我可能做错的任何建议。

【问题讨论】:

  • 你在哪里访问时间?它是在同一个用户请求中还是在代码中的其他地方?还是模板?
  • 我正在访问不同部分的时间。我在激活时区后立即引入了时间部分(更新了我的帖子),以确保它仍然是错误的并且仍然是。
  • 如果它工作正常,它会在模板或其他用户请求中使用吗?
  • 如果它工作正常,它将在视图定义中使用,从而进入数据库。不幸的是,这里的时间是下午 12:20,它说它是晚上 7 点
  • 似乎生成的UTC时间是正确的

标签: django python-2.7 timezone pytz


【解决方案1】:

这是我确保正确存储和显示时区和日期时间的一般方法。

首先确保USE_TZ = True 在您的settings.py 文件中,并确保TIME_ZONE='UTC' 也在那里。

因此,在向数据库添加日期时间时,请确保它们采用 UTC,以避免出现多个时区或夏令时的问题。

我通常按照本文底部的示例使用中间件设置会话时区。我只是将其更改为不再使用已弃用的 MiddlewareMixin (因此您需要 django 1.10+ 才能遵循此操作,否则请在下面查看更多内容)

import pytz

from django.utils import timezone

# make sure you add `TimezoneMiddleware` appropriately in settings.py
class TimezoneMiddleware(object):
    """
    Middleware to properly handle the users timezone
    """

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # make sure they are authenticated so we know we have their tz info.
        if request.user.is_authenticated():
            # we are getting the users timezone string that in this case is stored in 
            # a user's profile
            tz_str = request.user.profile.timezone
            timezone.activate(pytz.timezone(tz_str))
        # otherwise deactivate and the default time zone will be used anyway
        else:
            timezone.deactivate()

        response = self.get_response(request)
        return response

在调整它以正确使用用户时区后,确保将其添加到 settings.py 中的中间件

现在,当在模板中访问 datetime 对象时,它们将自动从数据库的“UTC”格式转换为用户所在的任何时区。只需访问 datetime 对象,它的时区将假设以前的中间件设置设置正确。

{{ my_datetime_value }}

如果您希望对是否使用用户的时区进行细粒度控制,请查看以下内容:

{% load tz %}
{% localtime on %}
    {# this time will be respect the users time zone #}
    {{ your_date_time }}
{% endlocaltime %}

{% localtime off %}
    {# this will not respect the users time zone #}
    {{ your_date_time }}
{% endlocaltime %}

https://docs.djangoproject.com/en/1.11/topics/i18n/timezones/



启用时区支持

首先,确保USE_TZ = True 在您的settings.py 文件中。还将默认时区值设置为TIME_ZONE,例如TIME_ZONE='UTC'。查看完整的时区列表here

如果 USE_TZ 为 False,TIME_ZONE 将是 Django 用于存储所有日期时间的时区。启用USE_TZ 时,TIME_ZONE 是 Django 用于在模板中显示日期时间并解释在表单中输入的日期时间的默认时区。

启用时区支持后,django 会将datetime 数据作为时区UTC 存储在数据库中



设置会话时区

Python 的datetime.datetime 对象有一个tzinfo 属性,用于存储时区信息。当属性被设置时,对象被认为是 Aware,当属性未被设置时,它被认为是 Naive。

为确保时区是幼稚或可感知的,您可以使用.is_naive().is_aware()

如果您在settings.py 文件中启用了USE_TZ,只要在settings.py 中设置了默认TIME_ZONEdatetime 就会附加时区信息

虽然此默认时区在某些情况下可能很好,但可能还不够,尤其是在您处理多个时区的用户时。为了做到这一点,必须使用中间件。

import pytz

from django.utils import timezone

# make sure you add `TimezoneMiddleware` appropriately in settings.py
class TimezoneMiddleware(object):
    """
    Middleware to properly handle the users timezone
    """

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # make sure they are authenticated so we know we have their tz info.
        if request.user.is_authenticated():
            # we are getting the users timezone that in this case is stored in 
            # a user's profile
            tz_str = request.user.profile.timezone
            timezone.activate(pytz.timezone(tz_str))
        # otherwise deactivate and the default time zone will be used anyway
        else:
            timezone.deactivate()

        response = self.get_response(request)
        return response

有一些新的事情正在发生。在__call__ 中,我们正在处理时区数据的设置。首先,我们确保用户已通过身份验证,以确保我们拥有该用户的时区数据。一旦我们知道我们这样做了,我们就会使用timezone.activate() 为用户会话激活时区。为了将时区字符串转换为日期时间可用的字符串,我们使用pytz.timezone(str)

现在,当在模板中访问 datetime 对象时,它们将自动从数据库的“UTC”格式转换为用户所在的任何时区。只需访问 datetime 对象,它的时区将假设以前的中间件设置设置正确。

{{ my_datetime_value }}

如果您希望对是否使用用户的时区进行细粒度控制,请查看以下内容:

{% load tz %}
{% localtime on %}
    {# this time will be respect the users time zone #}
    {{ your_date_time }}
{% endlocaltime %}

{% localtime off %}
    {# this will not respect the users time zone #}
    {{ your_date_time }}
{% endlocaltime %}

注意,这里描述的方法仅适用于 Django 1.10 及更高版本。要从 1.10 之前支持 django,请查看 MiddlewareMixin

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-16
    • 1970-01-01
    • 1970-01-01
    • 2019-08-29
    • 2015-10-06
    • 1970-01-01
    • 2018-09-16
    • 2017-10-25
    相关资源
    最近更新 更多