Flask/Jinja模板中将UTC转换为本地时区

5

我知道这个问题以前已经被提出过,但我仍然在努力尝试解决这个问题。我尝试了pytz、dateutil和flask_moment,但仍然无法将UTC格式的MySQL表格中的日期时间转换为本地时间(具体为UTC-05:00(东部标准时间))并在jinja2模板中显示。

我的jinja2循环代码如下:

{% for data in items %}
    ...
   <td>{{data.loggedInBy}}</td>
   <td>{{data.timeIn.strftime('%I:%M %p')}}</td>
    ...
{% endfor %}

我刚接触python/flask/jinja,所以请大家温柔一点。对于像我这样的新手来说,文档有些令人困惑。可以有人帮帮我,指导如何在本地时区中显示MySQL表格中的时间吗?

我感觉这个方法已经接近正确,但是还是出现了错误。在 init.py 中,我写了以下内容:

from pytz import timezone

def datetimefilter(value, format='%I:%M %p'):
    tz = timezone('US/Eastern')
    dt = value
    local_dt = tz.localize(dt)
    local_dt.replace(hour=local_dt.hour + int(local_dt.utcoffset().total_seconds() / 3600))
    return local_dt.strftime(format)

flask_app.jinja_env.filters['datetimefilter'] = datetimefilter

jinja template had:

{% for data in items %}
...
<td>{{data.loggedInBy}}</td>
<td>{{data.timeIn | datetimefilter }}</td>
...
{% endfor %}

但是这给我带来了“ValueError: hour must be in 0..23”的错误。 出错代码行为:

local_dt.replace(hour=local_dt.hour + int(local_dt.utcoffset().total_seconds() / 3600))

提前感谢您!

3个回答

9

在这种情况下,以下是适用于我的解决方案。我仍然不确定它是否会在夏令时期间提供错误的信息,但我们会看到的。

import pytz
from pytz import timezone
import tzlocal 

def datetimefilter(value, format="%I:%M %p"):
    tz = pytz.timezone('US/Eastern') # timezone you want to convert to from UTC
    utc = pytz.timezone('UTC')  
    value = utc.localize(value, is_dst=None).astimezone(pytz.utc)
    local_dt = value.astimezone(tz)
    return local_dt.strftime(format)

flask_app.jinja_env.filters['datetimefilter'] = datetimefilter

然后我的jinja2模板如下:
{% for data in items %}
...
<td>{{data.loggedInBy}}</td>
<td>{{data.timeIn | datetimefilter }}</td>
...
{% endfor %}

如果有任何改进的方法,我愿意听取建议,但到目前为止,这是我找到的唯一有效的方法。

这就是我在寻找的东西。谢谢。 - twk

1
本地化不会改变时区,而是向原始日期时间对象添加时区信息。您说您的日期时间来自SQL并且在UTC中,但它是一个时区感知的日期时间对象吗?如果value是一个意识到它是UTC而不是原始日期时间对象的日期时间对象,您应该像这样更改时区。
tz = pytz.timezone('US/Eastern')  # timezone you want to convert to from UTC
local_dt = value.astimezone(tz)
return local_dt.strftime(format)

如果您收到以下错误信息
ValueError: astimezone() cannot be applied to a naive datetime
那么您的value是一个纯日期时间对象,您需要将其转换为时区感知的UTC时间,然后再获取本地化的日期时间。
tz = pytz.timezone('US/Eastern')
utc = pytz.timezone('UTC')
tz_aware_dt = utc.localize(value)
local_dt = tz_aware_dt.astimezone(tz)
return local_dt.strftime(format)

有多种方法可以检查您的日期时间对象是否是naive。例如,如果它意识到它的时区value.tzname()将返回时区的名称,否则将返回none。

时区感知:datetime.datetime(2016, 1, 1, 4, 28, 26, 149703, tzinfo=<DstTzInfo 'US/Eastern' EST-1 day, 19:00:00 STD>)

Naive日期时间对象:datetime.datetime(2016, 1, 1, 9, 28, 26, 149703)


谢谢Schechter,但是即使在您的第二个建议之后,我仍然遇到了ValueError:astimezone()无法应用于naive datetime的问题。离成功还有一步之遥,但对我来说仍然不太行。 - Ryan Greever
是的,Schechter,看起来读取tz_aware_dt = utc.localize(value)的那一行应该改为:tz_aware_dt = utc.localize(value).astimezone(pytz.utc)才能真正地使它意识到。 - Ryan Greever
感谢 @RyanGreever 指出这个问题。我原本把'value'写成了tz_aware_dt,现在已经修改回来了。 - Schechter
1
从Python 3.6开始,可以在naive datetime上调用astimezone(),并且它将被假定为本地时区。注意这一点! - NeverCast

1

Flask-Moment可以在这种情况下很好地使用。详细说明请查看链接。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接