Web 應用中日期時間顯示看似簡單,實則暗藏時區陷阱。本文分析服務端 UTC 存儲與客戶端本地化顯示的矛盾,推薦 **Moment.js 客戶端渲染方案**,實現零配置、文化感知、格式豐富的時間顯示。
| 方案 | 優點 | 缺點 |
|---|---|---|
| 伺服器端轉換 | 模板直接輸出 HTML,SEO 友好 | 需維護用戶時區配置;格式本地化困難(AM/PM、日期順序、語言) |
| 客戶端轉換 (推薦) | 瀏覽器原生獲取系統時區/格式;零配置;Moment.js 功能極強 | 需 JS 執行;SEO 需額外處理(SSR/預渲染) |
Moment.js:輕量、免費、開源 JS 庫,解析、驗證、操作、格式化日期時間。核心優勢:
format('LLLL') → "Tuesday, January 1 2013 7:55 AM"fromNow() → "2 hours ago"calendar() → "Today at 7:55 AM"下載 moment.min.js 至 app/static/js/,模板引入:
<script src="{{ url_for('static', filename='js/moment.min.js') }}"></script>
視圖函數傳遞 datetime.utcnow() 或模型字段,模板輸出 ISO 格式:
<!-- 假設 post.timestamp 為 UTC datetime 對象 -->
<span class="timestamp" data-utc="{{ post.timestamp.isoformat() }}Z"></span>
Z 後綴標識 UTC,Moment.js 直接解析。
<script>
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('.timestamp').forEach(function(el) {
var utc = el.getAttribute('data-utc');
if (utc) {
// 格式化顯示
el.textContent = moment(utc).format('LLLL');
// 或相對時間
// el.textContent = moment(utc).fromNow();
}
});
});
</script>
pip install flask-moment 封裝上述邏輯,提供模板宏:
{% from 'momentjs.html' import moment %}
{{ moment(post.timestamp).format('LLLL') }}
{{ moment(post.timestamp).fromNow() }}
內部原理相同:模板輸出 <script>moment(...).format(...);</script>。
datetime.utcnow(),避免時區混亂。dt.isoformat() + 'Z',無歧義、可直接 moment() 解析。document.write:僅在文檔加載階段有效,AJAX 動態內容失效。改用 DOM 操作(如上示例)。<noscript> 顯示 UTC 時間或提示啟用 JS。Intl.DateTimeFormat(現代瀏覽器已完善支援)。**「UTC 存儲 + ISO 傳輸 + 客戶端 Moment.js 渲染」** 是處理全球化時間顯示的經典最佳實踐。它將時區/格式複雜性下沉到瀏覽器原生能力與成熟庫,伺服器端保持極簡,用戶體驗零配置自適應。現代項目可評估原生 Intl API 替代 Moment.js,進一步減少依賴。