我正在尝试在烧瓶应用程序中将UTC时间转换为适当的本地时间。我想知道我是否可以检测用户的时区并动态设置它。
这是我到目前为止的代码,仅适用于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
来处理这个问题?
如果你想在网站上动态检测用户的本地时间,最简单的方法是通过JavaScript Date()对象获取浏览器的datetime。这样,您可以显示正确的本地时间,而无需在字面意义上检测任何内容。您的代码段可能如下所示:
@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对其进行验证,并将其保留在用户的会话中。
请注意,类似的问题之前已经回答过。
下面是使用现代浏览器 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://stackoverflow.com/a/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 %}