本文翻译自The Flask Mega-Tutorial Part XII: Dates and Times

这是Flask Mega-Tutorial系列的第十二部分,我将告诉你如何以适配所有用户的方式处理日期和时间,无论他们身处地球上的何处。

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

本章的GitHub链接为:BrowseZipDiff.

时区地狱

使用服务器端的Python渲染日期和时间来展示到用户的浏览器并非一个好主意。考虑如下的例子, 我在2017年9月28日下午4点06分写这篇文章。我身处的时区是PDT(UTC-7),在Python解释器中运行如下:

>>> from datetime import datetime
>>> str(datetime.now())
'2017-09-28 16:06:30.439388'
>>> str(datetime.utcnow())
'2017-09-28 23:06:51.406499'

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

很明显,服务器必须管理一致且独立于位置的时间。 如果这个应用增长到在全世界不同地区都需要部署生产服务器的时候,我不希望每个服务器都在写入不同时区的时间戳到数据库,因为这会导致其无法正常地运行。 由于UTC是最常用的统一时区,并且在datetime类中也受到支持,因此我将会使用它。

但这种方法存在一个严重问题。 对处于不同时区的用户,如果他们看到的是UTC时区中的时间,那么很难确定是何时发布的信息。 他们需要事先知道展示的时间是UTC时区的,才能在精神上调整自己的时区。 设想一下PDT时区中的一个用户在下午3点发布了一些内容,并立即看到该帖子以UTC时间表示的晚上10:00或更准确的22:00,这太混乱了。

从服务器的角度来说,将时间戳标准化为UTC,意义重大,但这会为用户带来可用性问题。 本章的目标就是解决该问题,同时保持服务器中以UTC格式管理的所有时间戳。 
While standardizing the timestamps to UTC makes a lot of sense from the server’s perspective, this creates a usability problem for users. The goal of this chapter is to address this problem while keeping all the timestamps managed in the server in UTC.

时区转换

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

许多网站都有一个配置页面供用户指定他们的时区。 这将需要我添加一个新的页面,其中我向用户显示带有时区列表的下拉列表。 也可能用户在第一次访问网站时,作为注册的一部分,会被要求输入他们的时区。

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

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

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

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

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

Moment.js和Flask-Moment简介

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

因此,让我们从安装Flask-Moment来开始吧:

(venv) $ pip install flask-moment

使用常规方法添加该插件到Flask应用中:

app/__init__.py:Flask-Moment实例。

# ...
from flask_moment import Moment app = Flask(__name__)
# ...
moment = Moment(app)

与其他插件不同的是,Flask-Moment与moment.js一起工作,因此应用的所有模板都必须包含moment.js。为了确保该库始终可用,我将把它添加到基础模板中,可以通过两种方式完成。 最直接的方法是显式添加一个<script>标签来引入库,但Flask-Moment的moment.include_moment()函数可以更容易地实现它,它直接生成了一个<script>标签并在其中包含moment.js:

app/templates/base.html:在基础模板中包含moment.js

...

{% block scripts %}
{{ super() }}
{{ moment.include_moment() }}
{% endblock %}

我在这里添加的scripts块是Flask-Bootstrap基础模板暴露的另一个块,这是JavaScript引入的地方。该块与之前的块不同的地方在于它已经在基础模板中定义了一些内容了。我想要追加moment.js库的话,就需要使用super()语句,才能继承基础模板中已有的内容,否则就是替换。

使用Moment.js

Moment.js为浏览器提供了一个moment类。 呈现时间戳的第一步是创建此类的对象,并以ISO 8601格式传递所需的时间戳。 这里是一个例子:

t = moment('2017-09-28T21:45:23Z')

如果你对日期和时间不熟悉ISO 8601标准格式,格式如下:{{ year }}-{{ month }}-{{ day }}T{{ hour }}:{{ minute }}:{{ second }}{{ timezone }}。 我已经决定我只使用UTC时区,因此最后一部分总是将会是Z,它表示ISO 8601标准中的UTC。

moment对象为不同的渲染选项提供了几种方法。 以下是一些最常见的几种:

moment('2017-09-28T21:45:23Z').format('L')
"09/28/2017"
moment('2017-09-28T21:45:23Z').format('LL')
"September 28, 2017"
moment('2017-09-28T21:45:23Z').format('LLL')
"September 28, 2017 2:45 PM"
moment('2017-09-28T21:45:23Z').format('LLLL')
"Thursday, September 28, 2017 2:45 PM"
moment('2017-09-28T21:45:23Z').format('dddd')
"Thursday"
moment('2017-09-28T21:45:23Z').fromNow()
"7 hours ago"
moment('2017-09-28T21:45:23Z').calendar()
"Today at 2:45 PM"

此示例创建了一个moment对象,该对象被初始化为2017年9月28日晚上9:45 UTC。 你可以看到,我上面尝试的所有选项都以UTC-7时区来呈现,因为这是我计算机上配置的时区。你可以在microblog上进行此操作,只要你引入了moment.js。或者你也可以在https://momentjs.com/上尝试。

请注意不同的方法是如何创建的不同的表示。 使用format(),你可以控制字符串的输出格式,类似于Python中的strftime函数。 fromNow()calendar()方法很有趣,因为它们会根据当前时间显示时间戳,因此你可以获得诸如“一分钟前”或“两小时内”等输出。

如果你直接在JavaScript中运行,则上述调用将返回渲染后的时间戳字符串。 然后,你可以将此文本插入页面上的适当位置,不幸的是,这需要JavaScript与DOM配合使用。 Flask-Moment插件通过启用一个类似于JavaScript上的moment对象,大大简化了对moment.js的使用,并融合了所需的JavaScript逻辑,使渲染后的时间展示在页面上。

我们来看看出现在个人主页中的时间戳。 当前的user.html模板使用Python生成时间的字符串表示。 现在我可以使用Flask-Moment渲染此时间戳,如下所示:

app/templates/user.html: 使用moment.js渲染时间戳。

                {% if user.last_seen %}
<p>Last seen on: {{ moment(user.last_seen).format('LLL') }}</p>
{% endif %}

如你所见,Flask-Moment使用的语法类似于JavaScript库的语法,其中一个区别是,moment()的参数现在是Python的datetime对象,而不是ISO 8601字符串。 从模板发出的moment()调用也会自动生成所需的JavaScript代码,以将呈现的时间戳插入DOM的适当位置。

我可以利用Flask-Moment和moment.js的第二个地方是被主页和个人主页调用的_post.html子模板。 在该模板的当前版本中,每条用户动态都以“用户名说:”行开头。 现在我可以添加一个用fromNow()渲染的时间戳:

app/templates/_post.html: 在用户动态子模板中渲染时间戳。

                <a href="{{ url_for('user', username=post.author.username) }}">
{{ post.author.username }}
</a>
said {{ moment(post.timestamp).fromNow() }}:
<br>
{{ post.body }}

下面,你可以看到这两个时间戳在Flask-Moment和moment.js的渲染下,表现如何:

https://blog.csdn.net/weixin_42126327/article/details/81901036

flask日期和时间的更多相关文章

  1. Flask从入门到精通之Flask-Moment本地化日期和时间

    Moment.js 是一个简单易用的轻量级JavaScript日期处理类库,提供了日期格式化.日期解析等功能.它支持在浏览器和NodeJS两种环境中运行.此类库能够 将给定的任意日期转换成多种不同的格 ...

  2. Flask 教程 第十二章:日期和时间

    本文翻译自The Flask Mega-Tutorial Part XII: Dates and Times 这是Flask Mega-Tutorial系列的第十二部分,我将告诉你如何以适配所有用户的 ...

  3. Flask学习之十三 日期和时间

    英文博客地址:http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-xiii-dates-and-times 中文翻译地址: ...

  4. flask_日期和时间

    不知道大家有没有发现,在我们学习flask的过程中,post的timestamp字段添加时间时一直用的是datetime.utcnow()来获取时间,但是它获取的时间跟本地时间不一样,下面我们来测试一 ...

  5. Flask-Moment本地化日期和时间

    moment.js客户端开源代码库,可以在浏览器中渲染日期和时间.Flask-Moment是一个flask程序扩展,能把moment.js集成到Jinja2模板中. 1.安装 pip install ...

  6. [Java]Java日期及时间库插件 -- Joda Time.

    来到新公司工作也有一个多月了, 陆陆续续做了一些简单的项目. 今天做一个新东西的时候发现了 Joda Time的这个东西, 因为以前用的都是JDK原生的时间处理API, 大家都知道Java原生的时间处 ...

  7. SharePoint 2013 日期和时间字段格式设置

    前言 最近碰到一个需求,用户希望修改日期和时间字段的格式,因为自己的环境是英文的,默认的时间格式是[月/日/年]这样的格式,我也是碰到这个问题才知道,这是美式的时间格式,然而用户希望变成英式的时间格式 ...

  8. MySQL 日期、时间转换函数

    MySQL 日期.时间转换函数:date_format(date,format), time_format(time,format) 能够把一个日期/时间转换成各种各样的字符串格式.它是 str_to ...

  9. python笔记7:日期和时间

    Python 提供了一个 time 和 calendar 模块可以用于格式化日期和时间. 时间间隔是以秒为单位的浮点小数. 每个时间戳都以自从1970年1月1日午夜(历元)经过了多长时间来表示. 时间 ...

随机推荐

  1. 关于ffmpeg的安装具体步骤和说明

    一.windows安装: 直接下载地址: https://ffmpeg.zeranoe.com/builds/ https://ffmpeg.zeranoe.com/builds/win64/stat ...

  2. C++第11周(春)项目3 - 点类派生直线类

    课程首页在:http://blog.csdn.net/sxhelijian/article/details/11890759.内有完整教学方案及资源链接 [项目3 - 点类派生直线类]定义点类Poin ...

  3. log4net preserveLogFileNameExtension 和 watch

    preserveLogFileNameExtension <log4net> <appender name="fileappender" type="l ...

  4. SVM中的线性分类器

    线性分类器: 首先给出一个非常非常简单的分类问题(线性可分),我们要用一条直线,将下图中黑色的点和白色的点分开,很显然,图上的这条直线就是我们要求的直线之一(可以有无数条这样的直线)     假如说, ...

  5. hdu 2222(AC自动机模版题)

    Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others ...

  6. mysql行列转置

    --创建行转列表及插入数据 create table tb_RowConvertToColumn ( username nvarchar(100) null, course nvarchar(100) ...

  7. ACM_写数字

    写数字 Time Limit: 2000/1000ms (Java/Others) Problem Description: 把由1开始的自然数依次写下来:123456789101112……,重新分组 ...

  8. Ubuntu下搭建repo服务器(一): 配置gitosis

    1. 说明 服务器端IP: 192.168.1.126,下文简称:A端: 客户端IP: 192.168.130.19,下文简称:B端: Android工程代号:17435. 2. 安装必要软件(A端) ...

  9. 团队作业-Beta版本发布

    这个作业属于哪个课程  <课程的链接>            这个作业要求在哪里 <作业要求的链接> 团队名称 Three cobblers 这个作业的目标 Beta版本发布报 ...

  10. 远程连接Oracle设置

    1:打开net manager:开始->程序->oracle->配置和移植工具->Net Manager 2:添加服务器名->名子自定义,一般根据项目自定义,自己知道就行 ...