【Flask/跟着學習】Flask大型教程項目#11:日期

跟着學習(新版):https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-xii-dates-and-times
回顧上一章:https://blog.csdn.net/weixin_41263513/article/details/85092856

本章內容

  • 時區轉換
  • Moment.js和Flask-Moment
  • 使用Moment.js

時區轉換

在datetime這個包內,datetime.now()調用返回我的位置的正確時間,而datetime.utcnow()調用返回UTC時區的時間,如果我可以讓生活在世界不同地區的很多人在同一時間與我一起運行上述代碼,datetime.now()函數將爲每個人返回不同的結果,但datetime.utcnow()將始終返回同一個時間,因此,服務器必須管理一致且獨立於位置的時間。

我不希望每個服務器在不同時區向數據庫寫入時間戳,這樣管理起來會非常混亂,由於UTC是最常用的統一時區,,並且在datetime類中受支持,所以UTC將會是最棒的選擇。但這種方法存在一個重要問題。對於不同時區的用戶,如果他們在UTC時區看到時間,那麼很難弄清楚發佈帖子的時間,服務器的角度將時間戳標準化爲UTC很有意義,但這會給用戶帶來體驗上的問題。本章的目標是解決此問題。

該問題的顯而易見的解決方案是將所有時間戳從存儲的UTC單位轉換爲每個用戶的本地時間。這允許服務器繼續使用UTC來保持一致性,同時爲每個用戶量身定製的即時轉換解決了可用性問題。該解決方案的棘手部分是瞭解每個用戶的位置。

我們可以從客戶的計算機中獲取時區信息,從而在他們看不見的地方悄咪咪的把UTC單位轉換爲他們的本地時間。以下內容相當專業,可以適當瞭解

事實證明,Web瀏覽器知道用戶的時區,並通過標準的日期和時間JavaScript API公開它。實際上有兩種方法可以利用JavaScript提供的時區信息:

“old school”方法是在用戶首次登錄應用程序時讓Web瀏覽器以某種方式將時區信息發送到服務器。這可以通過Ajax調用完成,或者更簡單地使用元刷新標記完成。一旦服務器知道時區,它就可以將其保存在用戶的會話中,或者將其寫入數據庫中的用戶條目,然後在渲染模板時用它調整所有時間戳。
“new school”的方法是不改變服務器中的東西,並允許使用JavaScript在客戶端中進行從UTC到本地時區的轉換。
這兩個選項都是有效的,但第二個選項有很大的優勢。知道用戶的時區並不總是足以以用戶期望的格式呈現日期和時間。瀏覽器還可以訪問系統區域設置配置,該配置指定AM / PM與24小時制,DD / MM / YYYY與MM / DD / YYYY以及許多其他文化或區域樣式之類的內容。

如果這還不夠,那麼new school方法還有一個優勢。有一個開源庫可以完成所有這些工作!

Moment.js和Flask-Moment

Moment.js是一個小型的開源JavaScript庫,它可以將日期和時間渲染到一種格式。 前段時間我們創建了Flask-Moment,這是一個小型Flask擴展,可以很容易地將moment.js合併到應用程序中。記得別忘了pip install flask-moment

這個擴展要像其他flask的應用程序一樣先初始化
文件:/app/–init–.py

# ...
from flask_moment import Moment

app = Flask(__name__)
# ...
moment = Moment(app)

與其他擴展不同,Flask-Moment與moment.js一起使用,因此應用程序的所有模板都必須包含此庫。 爲確保此庫始終可用,我將在base.html中添加它。 這可以通過兩種方式完成。 最直接的方法是顯式添加導入庫的

...

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

我在這裏添加的block是由Flask-Bootstrap的基本模板導出的另一個塊。 這是包含JavaScript導入的地方。 此塊與以前的塊不同,因爲它已經在基本模板中定義了一些內容。 我想要做的就是添加moment.js庫,而不會丟失基本內容。 這是通過super()語句實現的,該語句保留了base.html中的內容。 如果在模板中定義塊而不使用super(),則基本模板中爲此塊定義的任何內容都將丟失

使用Moment.js

Moment.js爲瀏覽器提供了一個時刻類。渲染時間戳的第一步是創建此類的對象,以下是日期和時間的ISO 8601標準格式:
{{year}} - {{month}} - {{day}} T {{hour}}:{{minute} }:{{second}} {{timezone}}。
我已經決定我只使用UTC時區,所以最後一部分總是Z,它代表ISO 8601標準中的UTC。

moment對象爲不同的渲染選項提供了幾種方法。 以下是一些最常見的選項:

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

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"

此示例創建一個時刻對象,初始化時間爲2017年9月28日UTC時間下午9:45。您可以看到我在上面嘗試的所有選項都以UTC-7呈現

請注意不同方法如何創建不同的表示。使用format(),您可以使用格式字符串控制輸出的格式,類似於Python中的strftime函數。 fromNow()和calendar()方法很有趣,因爲它們呈現了與當前時間相關的時間戳,因此您可以獲得諸如“a minute ago”或“in two hours”等輸出。

Flask-Moment擴展通過在模板中啓用類似於JavaScript的時刻對象,極大地簡化了moment.js的使用

我們來看一下配置文件頁面中顯示的時間戳。當前的user.html模板允許Python生成時間的字符串表示。我現在可以使用Flask-Moment渲染此時間戳
文件:/app/templates/user.html

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

正如您所看到的,Flask-Moment使用的語法類似於JavaScript庫,但有一個區別是moment()的參數現在是Python日期時間對象而不是ISO 8601字符串。 從模板發出的moment()調用還會自動生成所需的JavaScript代碼,以將呈現的時間戳插入適當位置。

我可以利用Flask-Moment和moment.js的第二個地方是_post.html子模板,它是從index和user頁面調用的
文件:/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 }}

這章其實非常簡單,但也十分有必要,讓我們來看看效果把!
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章