Flask:将UTC时间转换为用户本地时间

9
我正在尝试将协调世界时(UTC)时间转换为适当的本地时间在flask应用程序中。 我想知道是否可以检测用户的时区并动态设置它。这是目前为止仅适用于US / Pacific时区的代码(datetimefilter来自这个SO问题)。
from flask import Flask, render_template_string
import datetime
import pytz

app = Flask(__name__)

@app.template_filter('datetimefilter')
def datetimefilter(value, format='%b %d %I:%M %p'):
    tz = pytz.timezone('US/Pacific')  # timezone you want to convert to from UTC (America/Los_Angeles)
    utc = pytz.timezone('UTC')
    value = utc.localize(value, is_dst=None).astimezone(pytz.utc)
    local_dt = value.astimezone(tz)
    return local_dt.strftime(format)

@app.route('/')
def index():
    dt = datetime.datetime.utcnow()
    return render_template_string(
        '''
        <h4>UTC --> Local Time</h4>
        Datetime right now is:
        <p>{{ dt | datetimefilter }} (utc --> local)</p>
        ''',
        dt=dt, now=now)


if __name__ == '__main__':
    app.run(debug=True)

我想这个问题无法在服务器端处理,因为时区将始终设置为服务器所在的位置。有没有一种方法可以通过更改datetimefilter来解决这个问题?

2个回答

4
如果您想在网站上动态检测用户的本地时间,最简单的方法是通过JavaScript Date()对象获取浏览器的日期时间。这样,您可以显示正确的本地时间,而无需从字面上检测任何内容。您的代码片段可能如下所示:
@app.route('/')
def index():
    dt = datetime.datetime.utcnow()
    return render_template_string(
        '''
        <html><body>
        <h4>UTC --> Local Time</h4>
        Datetime right now is:
        <p>{{ dt | datetimefilter }} (utc)</p>
        <p><span id="timeNow"></span> (local)</p>
        <script>
        var elem = document.getElementById("timeNow")
        var now = new Date();
        var options = { month: 'short', day: '2-digit',
                        hour: 'numeric', minute: '2-digit' };
        elem.innerHTML = now.toLocaleString('en-us', options);
        </script>
        </body></html>
        ''',
        dt=dt)

根据用户的本地时间,它将呈现以下结果:

UTC --> Local Time
Datetime right now is:

Dec 02 06:20 PM (utc)

Dec 03, 4:20 PM (local)

然后,如果需要根据用户本地时间保存或处理某些数据,您可以添加另一个@app.route (使用POST方法)来从网站前端 通过AJAX接收该Date()值。
在后端接收后,您可能想要 解析 javascript的Date()对象(请注意,在这种情况下最好使用普通的getTime()方法,而不是toLocaleString()格式),将其转换为Python的datetime,通过例如webargs / marshmallow进行验证,并将其保留在用户的 会话中。
请注意,类似的问题已经 在早期得到了回答

0
这是一个使用现代浏览器API相对紧凑的解决方案。它使用Javascript获取浏览器的时区,将其发送到后端以存储在会话对象中,并使用存储的时区在Jinja过滤器中应用于任何UTC日期时间以将其转换为用户的时区。
import pytz

from flask import request, session


@app.route('/set_timezone', methods=['POST'])
def set_timezone():
    '''Get timezone from the browser and store it in the session object.'''
    timezone = request.data.decode('utf-8')
    session['timezone'] = timezone
    return ""

@app.template_filter('localtime')
def localtime_filter(value):
    '''Use timezone from the session object, if available, to localize datetimes from UTC.'''
    if 'timezone' not in session:
        return value

    # https://dev59.com/JZPea4cB1Zd3GeqP-As1#34832184
    utc_dt = pytz.utc.localize(value)
    local_tz = pytz.timezone(session['timezone'])
    local_dt = utc_dt.astimezone(local_tz)
    return local_dt

在您的基本模板的 <head> 元素中,添加以下内容以使浏览器在第一次页面加载时将其时区发送到 /set_timezone 路由:
{% if 'timezone' not in session %}
<script type="text/javascript">
  // Send browser's timezone to server for displaying dates/times in local timezone.
  const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
  fetch("/set_timezone", {method: 'POST', body: timezone});
</script> 
{% endif %}

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