【问题标题】:How do I get the visitor's current timezone then convert timezone.now() to string of the local time in Django 1.4?如何获取访问者的当前时区,然后将 timezone.now() 转换为 Django 1.4 中的本地时间字符串?
【发布时间】:2026-02-08 23:20:02
【问题描述】:

我知道现在使用 Django 1.4 的最佳做法是将所有 datetime 存储在 UTC 中,我同意这一点。我也明白所有时区对话都应该在模板级别完成,如下所示:

{% load tz %}

{% timezone "Europe/Paris" %}
    Paris time: {{ value }}
{% endtimezone %}

但是,我需要在 Python 中将 UTC 时间转换为 request 的本地时间。我无法使用模板标签,因为我使用 Ajax(更具体地说是 Dajaxice)以 JSON 格式返回字符串。

目前这是我的代码ajax.py:

# checked is from the checkbox's this.value (Javascript).
datetime = timezone.now() if checked else None

$ order_pk is sent to the Ajax function.
order = Order.objects.get(pk=order_pk)
order.time = datetime
order.save()

return simplejson.dumps({
    'error': False,
    'datetime': dateformat.format(datetime, 'F j, Y, P') if checked else 'None'
})

因此,即使当前时间是 EST 时间(我的本地时区)中的 April 14, 2012, 5:52 p.m.,JSON 响应也会返回 April 14, 2012, 9:52 p.m,因为那是 UTC 时间。

我还注意到 Django 为每个请求存储了一个名为 TIME_ZONE 的模板变量(实际上不是 request 变量的一部分),所以由于我是 America/New_York,我假设 Django 可以计算出每个访问者的自己的本地时区(基于 HTTP 标头)?

无论如何,所以我的问题有两个:

  1. 如何在我的ajax.py 中获取访问者的本地时区? (可能将其作为字符串参数传递,例如 {{ TIME_ZONE }}
  2. 使用访问者的本地时区,如何将 UTC timezone.now() 转换为本地时区并使用 Django 的 dateformat 输出为字符串?

编辑:@agf

timezone.now() 给出 USE_TZ = True 时的 UTC 时间:

# From django.utils.timezone
def now():
    """
    Returns an aware or naive datetime.datetime, depending on settings.USE_TZ.
    """
    if settings.USE_TZ:
        # timeit shows that datetime.now(tz=utc) is 24% slower
        return datetime.utcnow().replace(tzinfo=utc)
    else:
        return datetime.now()

有没有办法将datetime 转换为UTC 以外的值?例如,我可以先做current_time = timezone.now(),然后再做current_time.replace(tzinfo=est)(EST = 东部标准时间)吗?

【问题讨论】:

    标签: python django timezone


    【解决方案1】:

    您需要仔细阅读Django Timezones docs

    很重要的一点:

    没有等效的 Accept-Language HTTP 标头,Django 可以使用它来自动确定用户的时区。

    您必须询问用户他们的时区是什么,或者只使用默认时区。

    您还需要确保:

    USE_TZ = True
    

    在你的settings.py

    一旦你有一个时区tz,你可以:

    from django.utils import timezone
    
    timezone.activate(tz)
    
    datetime = timezone.now() if checked else None
    

    在时区tz 中获取时区感知datetime 对象。

    【讨论】:

    • 好吧,我首先必须在timezone.activate(tz) 之前执行timezone.now() 并将其存储到order,对吗?但是接下来会有2个不同的datetime
    • @hobbes3 如果您想要默认时区的时区感知日期时间,那么可以。如果您想要一个可感知时区的 UTC 日期时间,并且默认时区不是 UTC,那么您需要转换为 UTC。
    • @hobbes3 你可以随时使用somedatetime.replace(tz=sometz)
    • 是的,抱歉,我刚刚意识到我的第一条评论非常含糊。我的意思是说我想首先使用current_time = timezone.now() 捕获当前的UTC 时间,将其附加到order(将其存储到数据库中),然后使用相同的current_time,将其转换为ETC 或访问者的任何时区使用,然后将其转换为字符串,最后通过 Ajax 将其传递回 JavaScript。我希望这是有道理的。
    • @hobbes3 我假设由于您通过 JSON 发送的内容仅用于显示,它不必将存储在数据库中的时间匹配到微秒,因此完全安全使用两个不同的 datetime 对象,因此您根本不必在 UTC 和本地时区之间来回转换。但是,您始终可以在任一方向使用replace(tz=thetz),但timezone.now() 作为一种便利功能的目的是能够轻松地为您提供时区感知本地时间。
    【解决方案2】:

    虽然浏览器不会向服务器发送任何指示时区的标头,但 JavaScript 环境确实知道其当前时区。

    这有两个重要的影响:虽然服务器在初始请求中无法找到您当前的时区,但您可以发送一些 JavaScript 代码,这些代码将确定 TZ 偏移量并将该信息发回到服务器,以便从该点开始,区域信息可以与当前会话相关联。

    但更重要的是,如果您在 JSON 数据中发送时间值,该数据将由浏览器客户端解释,则浏览器的时区不需要知道。相反,您只需确保 JSON 输出中存在时区偏移量,以便浏览器可以在事后进行自己的时区数学运算。

    var now = new Date()
    var offset_minutes = now.getTimezoneOffset()  # e.g. 240 for GMT-0400
    

    【讨论】:

      【解决方案3】:

      由于您需要用户的时区,因此对我来说这应该在使用 Javascript 的浏览器上完成。

      我将这样的内容传递到模板中:

      {"t": str(obj.timestamp))
      

      其中 obj 是 django 模型的实例,其中时间戳字段的类型为 DateTimeField。

      模板:

      <div class="timestring">{{ t }}</div> 
      ...
      <script>
        $('.timestring').each(function(){
          var d = new Date($(this).text());
          $(this).text(d.toLocaleDateString() + ", " + d.toLocaleFormat("%r (%Z)"));
        })
      </script>
      

      对我来说,这会输出如下内容:2/15/2017, 05:22:24 PM (PST)

      相关文档:

      【讨论】:

        最近更新 更多