# Flask實作_ext_19_Flask-Moment ###### tags: `flask` `flask_ext` `python` `moment` :::danger 官方文件: * [Flask-Moment](https://github.com/miguelgrinberg/Flask-Moment) * Flask-Moment是由[Miguel Grinberg](https://github.com/miguelgrinberg)所開發,整合了Flask與Moment.js。 * [探查Python時間API|iThome](https://www.ithome.com.tw/voice/106285) * [Moment.js](http://momentjs.com/) ::: ## 說明: 世界時間有[時區](https://pansci.asia/archives/84978),臺灣所在為UTC +8,不同國家的人所在可能有不同的變化,舉例來說,跨年的時候都會發現,我們還在倒數的時候日本已經放完煙火在睡覺。因此相同時間點上,臺灣的20190101 00:00:00,不會是日本的20190101 00:00:00,因為臺灣的20190101 00:00:00已經是日本的20190101 01:00:00。 Moment.js主要處理日期與時間的本地化,即時間顯示依當地所在時區來呈現,因此在時間記錄上我們必需保持時間為`UTC TIME`,單純的`UTC TIME`,以下圖為例,`UTC TIME`與在下的時間相差了8個小時<sub>(更多資訊可參閱前置閱讀連結)</sub>,這也是為什麼我們在設置資料庫的時間記錄上都是`datetime.utcnow`的用意<sub>(注意,不是`datetime.utcnow()`)</sub>。 ![](https://i.imgur.com/fuhLhQF.png) ## 安裝 ```shell pip install flask_moment ``` ## 前置作業 ### 初始化 初始化的過程始終如一,如下: ```python= from flask import Flask from flask_moment import Moment app = Flask(__name__) moment = Moment(app) ``` 如果你所採用的是工廠函數的話,也可以這麼做: ```python moment.init_app(app) ``` ### 加入Template ```htmlmixed= <head> {{ moment.include_jquery() }} {{ moment.include_moment() }} </head> ``` 如果你已經有使用`Flask-Bootstrap`的話已經有載入JQuery了,可以單獨的載入Moment.js即可<sub>(`moment.include_moment()`)</sub>。 ## 範例 ### 建置Template ```htmlmixed= <!DOCTYPE html> <html lang="en"> <head> {{ moment.include_jquery() }} {{ moment.include_moment() }} <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>目前時間為..{{ moment(now).format('MMMM Do YYYY, h:mm:ss a') }}.</p> </body> </html> ``` ### 建置Python文件 ```python from flask import Flask, render_template from flask_moment import Moment from datetime import datetime, date app = Flask(__name__) moment = Moment(app) @app.route('/') def index(): now = datetime.utcnow() past_time = date(2018, 1, 1) return render_template('index.html', now=now, past_time=past_time) if __name__ == '__main__': app.debug = True app.run() ``` 執行結果如下: ![](https://i.imgur.com/QiDBa0Y.png) 可以明顯發現`now`雖然是`datetime.utcnow()`,但渲染至前端的時候已經依前端所在時區變更為當地時間。 ```python # 執行程式時候的UTC Time from datetime import datetime datetime.utcnow() datetime.datetime(2018, 12, 11, 13, 15, 32, 55644) ``` ### 變換語系 上面的測試我們發現到時區時間雖然正確了,但是格式的部份是英文,這對我們可能不是那麼直觀,可以利用`moment.locale("zh_TW")`定義,如下: ```htmlmixed= <head> {{ moment.include_jquery() }} {{ moment.include_moment() }} {{ moment.locale("zh_TW") }} <meta charset="UTF-8"> <title>Title</title> </head> ``` 第4行:加入`{{ moment.locale("zh_TW") }}`,變換語系為繁中,如下圖: ![](https://i.imgur.com/IFCLKCZ.png) 這樣子的作法除非你只有繁體中文的用戶,不然會建議讓程式自行從Client端判斷語系,調整設置如下: ```htmlmixed= <head> {{ moment.include_jquery() }} {{ moment.include_moment() }} {{ moment.locale(auto_detect=True) }} <meta charset="UTF-8"> <title>Title</title> </head> ``` 第4行:注意到參數並沒有以單、雙引號,執行如下: ![](https://i.imgur.com/4CQUOkM.png) ### 相對時間 在論壇查找資料的時候常會發現論壇顯示某一個文章已經發佈經過多久了,這部份Moment.js也可以實作。 我們在Html文件上加入兩行,如下: ```htmlmixed=10 <body> <p>目前時間為..{{ moment(now).format('MMMM Do YYYY, h:mm:ss a') }}.</p> <p>多少時間內..{{ moment(now).fromTime(past_time) }}</p> <p>已經經過了..{{ moment(past_time).fromTime(now) }}</p> </body> ``` 第12、13行:兩個參數放置不同位置觀察差異 執行結果如下: ![](https://i.imgur.com/7PYivkn.png) ### 格式化日期 Moment.js還提供了很多的格式化字串,這部份會建議依需求直接至官方查閱即可<sub>(見前置閱讀)</sub>,範例如下: ```htmlmixed= <div> <p>{{ moment(past_time).format('L') }}</p> <p>{{ moment().format('l') }}</p> <p>{{ moment(past_time).format('LL') }}</p> <p>{{ moment().format('ll') }}</p> <p>{{ moment(past_time).format('LLL') }}</p> <p>{{ moment().format('lll') }}</p> <p>{{ moment(past_time).format('LLLL') }}</p> <p>{{ moment().format('llll') }}</p> </div> ``` 執行結果如下: ![](https://i.imgur.com/fQSMkjB.png) 不同的格式化字串產生不同的時間日期結果,請務必查閱官方文件。 ### 自動更新 如果有到Github上查詢程式碼的話會發現有一個`refresh`的參數,主要用途是讓時間自動更新,因此可以完成`幾秒前`、`幾分前`...的功能,如下圖: ![](https://i.imgur.com/PD0FxR7.png) 這部份就實作專案中有應用到再範例說明。 ## 總結 Flask-Moment小而美,程式碼不多,建議可以看一下,了解它的功能與Moment.js的對應,有了Flask-Moment的幫助,我們就不擔心時間日期上的誤解了。 另外,可能有人會好奇,這部份的功能是否與Flask-Babel的時間、日期格式重覆了,這問題也困擾了在下很久,但個人解讀上,Flask-Babel算是屬於Server端的處理,而Flask-Moment屬於Client端的作業,如果理解上有錯再請指正。