12.日期和时间

在本章,我们将讨论怎么用适配不同时区的所有用户的方式来处理日期和时间,无论他们身处地球上的何处。

显示日期和时间是 Microblog 应用中长期被忽略的其中一个方面。直到现在,我也只是让 Python 渲染了 User 模型中的 datetime 对象,并且完全忽略了 Post 模型中的 datetime 对象。






时区地域

我们先来 Python shell 中看看这个例子:

>>> from datetime import datetime
>>> str(datetime.now())
'2021-08-02 17:09:16.366550'
>>> str(datetime.utcnow())
'2021-08-02 09:09:23.533968'

datetime.now() 调用返回我所处位置的本地时间,而 datetime.utcnow() 调用则返回 UTC 时区(协调世界时)中的时间。假设世界不同地区的多人同时运行上面的代码,datetime.now() 函数将为每个人返回不同的结果,但是无论身在哪个时区,datetime.utcnow() 总是会返回同一时间。那么你认为哪一个更适合用在一个用户遍布世界各地的 Web 应用中呢?

很明显,服务器必须管理一致且独立于位置的时间。我们肯定不希望每个用户都在写入不同时区的时间戳到数据库,因为这会导致其无法正常地运行。 UTC 是最常用的统一时区,并且在 datetime 类中受到支持,因此我将会使用它。

现在可以得出结论,对处于不同时区的用户,我们需要知道它的 UTC时间和所在的时区,再通过时区转换的计算,从而正确地为用户显示当地格式的时间。






时区转换

该问题的直接解决方案是将所有时间戳从存储的 UTC 单位转换为每个用户的本地时间。这样一来,服务器可以继续使用 UTC 来保持时区的一致性,而针对每个用户量身定制的即时转换来解决可用性问题。这个解决方案棘手的部分是要知道每个用户的位置。

其中一个解决方法是要求用户在个人资料处选择他们的时区。这将需要为此添加一个新的功能。也可以要求用户在第一次访问网站时,作为注册的一部分,会被要求选择他们的时区。

虽然该方案可以解决问题,但要求用户选择他们已经在其操作系统中配置的信息有点奇怪。 如果我能从他们的计算机操作系统中获取时区信息,似乎效率会更高。

其实通过 Web 浏览器就可以获取用户的时区,并通过标准的日期和时间 JavaScript API 暴露它。 有两种方法来利用 JavaScript 提供的时区信息:

  • “老派”方法是当用户第一次登录到应用程序时,Web 浏览器以某种方式将时区信息发送到服务器。这可以通过 Ajax 调用完成,或者更简单地使 meta refresh。一旦服务器知道了时区,就可以将其保存在用户的会话中,或者将其写入用户在数据库中的条目中,然后在渲染模板时从中调整所有时间戳。

  • “新派”的做法是不改变服务器中的东西,而在浏览器端使用 JavaScript 来对 UTC 和本地时区之间进行转换。

两种选择都是有效的,但第二种选择有很大优势。 光是知道用户的时区并不足以以用户期望的格式呈现日期和时间。 浏览器还可以访问系统区域配置,该配置指定 AM/PM 与 24 小时制,DD/MM/YYYYMM/DD/YYYY,以及许多其他文化或地区风格之类的东西。

如果这还不够,新派方法还有另一个优势,用一个开源的库来完成所有这些工作!






Moment.js 和 Flask-Moment 简介

Moment.js 是一个小型的 JavaScript 开源库,它将日期和时间转换成目前可以想象到的所有格式。而 Flask-Moment,一个小型 Flask 插件,它可以使你在应用中轻松使用 moment.js

我们还是从安装 Flask-Moment 来开始:

(venv) $ pip install flask-moment

一如既往,在 app\__init__.py 中初始化插件:

# app\__init__.py

from flask_moment import Moment

moment = Moment()

def create_app(config):
    app = Flask(__name__)
    moment.init_app(app)
    # ...
    return app

与其他插件不同的是,Flask-Moment 需要与 moment.js 一起工作,因此应用的所有模板都必须包含 moment.js。为了确保该库始终可用,我将把它添加到基础模板 base.html 中,可以通过两种方式完成。 最直接的方法是显式添加一个

你可能感兴趣的:(12.日期和时间)