JavaScript 日期與時間格式化(toLocaleString 等)
簡介
在前端開發中,日期與時間是最常見的資料類型之一。無論是顯示文章發佈時間、計算倒數計時,或是與後端 API 交換時間戳,正確且易讀的日期格式都是使用者體驗的關鍵。
傳統上,我們會使用 Date 物件的 getFullYear()、getMonth() 等方法自行拼接字串,但這種做法不僅繁瑣,還容易忽略 時區、本地化(locale)等細節。
ECMAScript 內建的 toLocaleString、toLocaleDateString、toLocaleTimeString 等方法,讓我們可以一次完成本地化、時區與格式的設定,省去大量手動處理的工作。本篇文章將深入探討這些方法的用法,並提供實務範例、常見陷阱與最佳實踐,幫助你在 JavaScript 中自信地處理日期格式化。
核心概念
1. Date 物件的基本操作
在深入本地化之前,先了解 Date 物件的建立與基本屬性:
// 建立目前時間的 Date 物件
const now = new Date();
// 取得各個時間單位(回傳的是數值)
console.log(now.getFullYear()); // 2025
console.log(now.getMonth()); // 0~11,0 代表 1 月
console.log(now.getDate()); // 1~31
console.log(now.getHours()); // 0~23
console.log(now.getMinutes()); // 0~59
console.log(now.getSeconds()); // 0~59
注意:月份是從 0 開始計算,若要顯示「1 月」需要自行加 1。
2. 為什麼要使用 toLocaleString 系列?
toLocaleString、toLocaleDateString、toLocaleTimeString 皆接受兩個參數:
dateObj.toLocaleString([locales], [options])
| 參數 | 說明 |
|---|---|
locales |
字串或字串陣列,指定要使用的語系(例:'zh-TW'、'en-US')。若省略,會使用執行環境的預設語系。 |
options |
物件,設定想要顯示的欄位與格式(如 year: 'numeric'、hour12: false)。 |
使用這兩個參數,我們可以一次決定 語系、本地化文字、時間格式、時區,而不必自行拼接或使用第三方函式庫。
3. 常見的 options 屬性
| 屬性 | 可能的值 | 說明 |
|---|---|---|
year |
'numeric'、'2-digit' |
顯示完整年份或兩位數年份 |
month |
'numeric'、'2-digit'、'short'、'long' |
數字、兩位數、縮寫或全名 |
day |
'numeric'、'2-digit' |
日期 |
weekday |
'short'、'long' |
星期幾 |
hour |
'numeric'、'2-digit' |
小時 |
minute |
'numeric'、'2-digit' |
分鐘 |
second |
'numeric'、'2-digit' |
秒 |
hour12 |
true、false |
12 小時制或 24 小時制 |
timeZone |
時區字串(例:'Asia/Taipei') |
指定顯示的時區 |
timeZoneName |
'short'、'long' |
顯示時區縮寫或全名 |
4. 範例一:基本的本地化日期字串
const date = new Date('2025-03-15T14:30:00');
// 台灣(zh-TW)顯示完整日期與時間(24 小時制)
const twFull = date.toLocaleString('zh-TW', {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false,
timeZone: 'Asia/Taipei',
});
console.log(twFull); // => 2025年3月15日 14:30:00
說明:month: 'long' 會輸出「3月」的全名,hour12: false 強制使用 24 小時制,timeZone 確保即使伺服器在不同時區,仍以台北時間顯示。
5. 範例二:僅顯示日期(不含時間)並加上星期
const today = new Date();
const options = {
weekday: 'short', // Wed、Thu…
year: 'numeric',
month: 'short', // Mar、Apr…
day: 'numeric',
};
console.log(today.toLocaleDateString('en-US', options));
// 例:Thu, Mar 12, 2025
說明:weekday: 'short' 會顯示縮寫的星期,month: 'short' 產生英文縮寫月份。若改成 'zh-TW',結果會是「星期四 3月 12日 2025」。
6. 範例三:自訂時間格式(12 小時制 + AM/PM)
const time = new Date('2025-03-15T09:05:07');
const formatted = time.toLocaleTimeString('en-US', {
hour: 'numeric',
minute: '2-digit',
second: '2-digit',
hour12: true, // 12 小時制
timeZone: 'America/New_York',
timeZoneName: 'short', // 顯示縮寫時區 (EDT)
});
console.log(formatted); // => 5:05:07 AM EDT
說明:hour12: true 會自動加上 AM/PM,timeZoneName: 'short' 把時區縮寫加入字串,方便使用者了解時間來源。
7. 範例四:多語系切換(國際化)
const eventDate = new Date('2025-12-31T23:59:59');
// 依不同語系產生不同格式
const locales = ['zh-TW', 'en-US', 'ja-JP'];
locales.forEach(loc => {
const str = eventDate.toLocaleString(loc, {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
hour12: loc === 'en-US', // 只在美式英語使用 12 小時制
timeZone: 'Asia/Taipei',
});
console.log(`${loc}: ${str}`);
});
/* 輸出範例
zh-TW: 2025年12月31日 23:59
en-US: December 31, 2025, 11:59 PM
ja-JP: 2025年12月31日 23:59
*/
說明:透過迴圈一次產出多語系的日期字串,適合在多國語系網站上動態切換。
8. 範例五:以 Intl.DateTimeFormat 建立可重複使用的 formatter
如果在大量資料(例如列表或表格)中頻繁格式化日期,直接呼叫 toLocaleString 會產生不必要的物件建立成本。可以先建立 Intl.DateTimeFormat 實例,再重複使用:
// 建立一次 formatter
const formatter = new Intl.DateTimeFormat('zh-TW', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
hour12: false,
timeZone: 'Asia/Taipei',
});
// 在迴圈中使用
const timestamps = [
1735680000000, // 2025-01-01 00:00:00 UTC
1735766400000, // 2025-01-02 00:00:00 UTC
// ...
];
timestamps.forEach(ts => {
console.log(formatter.format(new Date(ts)));
});
// 2025/01/01 08:00
// 2025/01/02 08:00
說明:formatter.format 只接受 Date 或時間戳,效能比每次呼叫 toLocaleString 好。
常見陷阱與最佳實踐
| 陷阱 | 說明 | 解決方案 |
|---|---|---|
| 時區不一致 | Date 物件在建立時會根據本機時區解讀字串,若直接使用 new Date('2025-03-15'),會被視為 UTC+0 的午夜,導致跨時區時差。 |
使用 ISO 8601 完整字串(包含時區)或在 toLocaleString 指定 timeZone。 |
| 月份從 0 開始 | 手動拼接日期時忘記加 1,導致顯示錯誤的月份。 | 盡量使用本地化方法,或在自行處理時 month + 1。 |
| 瀏覽器支援差異 | 部分舊版瀏覽器(IE)不支援 toLocaleString 的 options 參數,會回傳不符合預期的字串。 |
在需要兼容的情況下使用 polyfill(如 core-js)或第三方函式庫(date-fns、dayjs)。 |
hour12 與語系衝突 |
某些語系(如 zh-TW)預設是 24 小時制,若強制 hour12: true 可能產生不自然的顯示。 |
根據使用者語系自行決定 hour12,或提供 UI 切換選項。 |
timeZoneName 產生的字串長度 |
在 UI 空間有限的情況下,timeZoneName: 'long' 會產生「Coordinated Universal Time」之類的長字串。 |
使用 'short' 或自行省略時區顯示。 |
最佳實踐:
- 統一時區:在前端與後端溝通時,約定使用 UTC 或特定時區(如
Asia/Taipei),避免因本機時區差異產生錯誤。 - 使用
Intl.DateTimeFormat:大量渲染時,先建立 formatter 再重複使用,可提升效能。 - 根據使用者語系自動切換:
navigator.language可取得瀏覽器語系,配合toLocaleString自動產生符合當地慣例的格式。 - 避免手動拼接:盡量使用內建的本地化方法,減少錯誤與維護成本。
- 測試跨時區:在開發階段使用不同時區的模擬器(Chrome DevTools → Sensors)驗證顯示是否正確。
實際應用場景
1. 文章發佈時間顯示
在部落格或新聞網站,常見需求是「2025 年 3 月 15 日 14:30」的顯示。使用 toLocaleString 可一次完成:
function formatPostDate(timestamp) {
return new Date(timestamp).toLocaleString('zh-TW', {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
hour12: false,
timeZone: 'Asia/Taipei',
});
}
2. 跨國電商的訂單時間
電商平台需要同時呈現 使用者本地時間 與 系統(UTC)時間:
const orderTimeUTC = '2025-04-01T08:15:00Z';
const userLocale = navigator.language || 'en-US';
const local = new Date(orderTimeUTC).toLocaleString(userLocale, {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
hour12: false,
timeZoneName: 'short',
});
const utc = new Date(orderTimeUTC).toISOString().replace('T', ' ').substring(0, 16) + ' UTC';
console.log(`訂單時間(本地):${local}`);
console.log(`訂單時間(UTC):${utc}`);
3. 行事曆或排程系統的時區切換
允許使用者自行選擇時區(例如會議跨時區):
function formatForTimezone(date, tz) {
return date.toLocaleString('zh-TW', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
hour12: false,
timeZone: tz,
timeZoneName: 'short',
});
}
// 範例:顯示同一時間在台北、紐約、倫敦的差異
const meeting = new Date('2025-06-10T15:00:00Z');
console.log('台北:', formatForTimezone(meeting, 'Asia/Taipei'));
console.log('紐約:', formatForTimezone(meeting, 'America/New_York'));
console.log('倫敦:', formatForTimezone(meeting, 'Europe/London'));
4. 報表匯出(CSV/Excel)中的日期字串
匯出時常需要把日期轉成 ISO 8601 或 固定格式,避免使用者在 Excel 中自動轉換:
function toCSVDate(date) {
// 2025-03-15 14:30:00
return date.toLocaleString('sv-SE', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false,
timeZone: 'Asia/Taipei',
}).replace(' ', 'T');
}
總結
- 日期與時間的本地化 不只是字串的翻譯,更涉及時區、12/24 小時制、星期與月份名稱等多層面的調整。
- JavaScript 內建的
toLocaleString、toLocaleDateString、toLocaleTimeString搭配Intl.DateTimeFormat,提供了 一致、可讀且效能友善 的解決方案。 - 在實務開發中,統一時區、使用 formatter、根據使用者語系自動切換 是避免錯誤與提升使用者體驗的關鍵。
- 透過本文的範例,你可以快速在部落格、電商、行事曆與報表等常見情境中,正確且優雅地呈現日期與時間。
掌握這些技巧後,你將能在任何前端專案裡,輕鬆處理日期格式化的挑戰,讓使用者感受到更貼近生活的時間資訊。祝開發順利! 🚀