JavaScript日期時間操作完整指南!
標準化時間
標準化時間是指使用一套公認的標準來表示和衡量時間的方法。這種標準化使得不同地區和系統之間能夠統一地解讀和比較時間。目前最常用的標準化時間系統是協調世界時(Coordinated Universal Time,簡稱UTC)。UTC 是基于原子鐘的國際標準時間,被廣泛應用于全球各個領域,包括科學、航空、計算機網絡等。
在 Web 應用中,只要知道用戶所在的時區,就可以隨時轉換、展示時間。如果知道用戶當地的時間和時區,就可以將其轉換為 UTC。計算機中的時間采用 ISO 日期格式,它是 ISO-8601 擴展格式的簡化版本,如下所示:
日期/時間操作
下面先來看看如何使用 JavaScript 進行日期/時間操作。
Date對象
Date 對象基于 Unix Time Stamp,即自 1970 年 1 月 1 日(UTC)起經過的毫秒數。其語法如下:
new Date();
new Date(value);
new Date(dateString);
new Date(year, monthIndex [, day [, hours [, minutes [, seconds [, milliseconds]]]]]);
注意, 創建一個新Date對象的唯一方法是通過 new 操作符,例如:let now = new Date(); 若將它作為常規函數調用(即不加 new 操作符),將返回一個字符串,而非 Date 對象。
獲取當前時間
const currentDate = new Date();
如果不向 Date 構造函數傳遞任何內容,則返回的日期對象就是當前的日期和時間。然后,就可以將其格式化為僅提取日期部分,如下所示:
const currentDate = new Date();
const currentDayOfMonth = currentDate.getDate();
const currentMonth = currentDate.getMonth();
const currentYear = currentDate.getFullYear();
const dateString = currentDayOfMonth + "-" + (currentMonth + 1) + "-" + currentYear;
// '4-7-2023'
需要注意,月份是從 0 開始的,一月就是 0,依此類推。
獲取當前時間戳
可以創建一個新的 Date 對象并使用 getTime() 方法來獲取當前時間戳:
const currentDate = new Date();
const timestamp = currentDate.getTime();
在 JavaScript 中,時間戳是自 1970 年 1 月 1 日以來經過的毫秒數。如果不需要支持<IE8,可以使用Date.now()
直接獲取時間戳,而無需創建新的 Date 對象。
解析日期
可以通過不同的方式將字符串轉換為 JavaScript 日期對象。Date 對象的構造函數接受多種日期格式:
const date1 = new Date("Wed, 27 July 2016 13:30:00");
const date2 = new Date("Wed, 27 July 2016 07:45:00 UTC");
const date3 = new Date("27 July 2016 13:30:00 UTC+05:45");
需要注意,這里字符串不需要包含星期幾,因為 JS 可以確定任何日期是星期幾。
我們還可以傳入年、月、日、小時、分鐘和秒作為單獨的參數:
const date = new Date(2016, 6, 27, 13, 30, 0);
當然,也可以使用 ISO 日期格式:
const date = new Date("2016-07-27T07:45:00Z");
但是,如果不明確提供時區,就會有問題:
const date1 = new Date("25 July 2016");
const date2 = new Date("July 25, 2016");
date1 === date2; // false
這兩個都會展示當地時間 2016 年 7 月 25 日 00:00:00,但是兩者是不相等的。
如果使用 ISO 格式,即使只提供日期而不提供時間和時區,它也會自動接受時區為 UTC。
new Date("25 July 2016").getTime() !== new Date("2016-07-25").getTime()
new Date("2016-07-25").getTime() === new Date("2016-07-25T00:00:00Z").getTime()
設置日期格式
現代 JavaScript 在標準命名空間中內置了一些方便的國際化函數Intl,使日期格式化變得簡單。
為此,我們需要兩個對象:Date 和 Intl.DateTimeFormat,并使用輸出首選項進行初始化。假設想使用美國 (M/D/YYYY) 格式,則如下所示:
const firstValentineOfTheDecade = new Date(2020, 1, 14);
const enUSFormatter = new Intl.DateTimeFormat('en-US');
console.log(enUSFormatter.format(firstValentineOfTheDecade));
// 2/14/2020
如果想要荷蘭 (D/M/YYYY) 格式,只需將不同的區域性代碼傳遞給 DateTimeFormat 構造函數即可:
const nlBEFormatter = new Intl.DateTimeFormat('nl-BE');
console.log(nlBEFormatter.format(firstValentineOfTheDecade));
// 14/2/2020
或者美國格式的較長形式,并拼寫出月份名稱:
const longEnUSFormatter = new Intl.DateTimeFormat('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
});
console.log(longEnUSFormatter.format(firstValentineOfTheDecade));
// February 14, 2020
更改日期格式
我們知道了如何解析日期并對其進行格式化,將日期從一種格式更改為另一種格式只需將兩者結合起來即可。
例如,如果日期格式為 Jul 21, 2013,并且想要將格式更改為 21-07-2013,可以這樣實現:
const myDate = new Date("Jul 21, 2013");
const dayOfMonth = myDate.getDate();
const month = myDate.getMonth();
const year = myDate.getFullYear();
function pad(n) {
return n<10 ? '0'+n : n
}
const ddmmyyyy = pad(dayOfMonth) + "-" + pad(month + 1) + "-" + year;
// "21-07-2013"
本地化日期
上面討論的日期格式化方法應該適用于大多數應用,但如果想本地化日期的格式,建議使用 Date 對象的toLocaleDateString()方法:
const today = new Date().toLocaleDateString('en-GB', {
day: 'numeric',
month: 'short',
year: 'numeric',
});
console.log(today); // '4 Jul 2023'
如果想顯示日期的數字版本,建議使用以下解決方案:
const today = new Date().toLocaleDateString(undefined, {
day: 'numeric',
month: 'numeric',
year: 'numeric',
});
這里輸出了 7/26/2016. 如果想確保月份和日期是兩位數,只需更改選項:
const today = new Date().toLocaleDateString(undefined, {
day: '2-digit',
month: '2-digit',
year: 'numeric',
});
這樣就會輸出 07/26/2016。
還可以使用其他一些相關函數來本地化時間和日期的顯示方式:
計算相對日期和時間
下面是在 JavaScript 日期中添加 20 天的示例(即計算出已知日期后 20 天的日期):
const myDate = new Date("July 20, 2016 15:00:00");
const nextDayOfMonth = myDate.getDate() + 20;
myDate.setDate(nextDayOfMonth);
const newDate = myDate.toLocaleString();
原始的日期對象現在表示7月20日之后20天的日期,newDate包含的是表示該日期的本地化字符串。newDate的值是2016/8/9 15:00:00。
要計算相對時間戳,并得到更精確的差異,可以使用Date.getTime()和Date.setTime()來處理表示自某個特定時刻(即1970年1月1日)以來的毫秒數的整數。例如,如果想知道距離現在17小時后的時間:
const msSinceEpoch = (new Date()).getTime();
const seventeenHoursLater = new Date(msSinceEpoch + 17 * 60 * 60 * 1000);
比較時間
在比較時間時,首先需要創建日期對象,<、>、<= 和 >= 都可以工作。 因此,比較 2014 年 7 月 19 日和 2014 年 7 月 18 日就很簡單:
const date1 = new Date("July 19, 2014");
const date2 = new Date("July 28, 2014");
if(date1 > date2) {
console.log(date1);
} else {
console.log(date2);
}
檢查相等性比較棘手,因為表示同一日期的兩個日期對象仍然是兩個不同的日期對象并且不相等。 比較日期字符串不是一個好主意,因為例如“July 20, 2014”和“20 July 2014”表示相同的日期,但具有不同的字符串表示形式。 下面的代碼片段說明了第一點:
const date1 = new Date("June 10, 2003");
const date2 = new Date(date1);
const equalOrNot = date1 == date2 ? "相等" : "不等";
console.log(equalOrNot);
這里將輸出“不等”,這種特殊情況可以通過比較日期的時間戳來解決,如下所示:
date1.getTime() == date2.getTime()
這個例子不太符合實際的應用,因為通常不會從另一個日期對象創建日期對象。下面來看一個更實際的例子。比較用戶輸入的生日是否與從后端獲得的幸運日期相同。
const userEnteredString = "12/20/1989"; // MM/DD/YYYY format
const dateStringFromAPI = "1989-12-20T00:00:00Z";
const dateFromUserEnteredString = new Date(userEnteredString)
const dateFromAPIString = new Date(dateStringFromAPI);
if (dateFromUserEnteredString.getTime() == dateFromAPIString.getTime()) {
transferOneMillionDollarsToUserAccount();
} else {
doNothing();
}
兩者都代表相同的日期,但不幸的是用戶將無法獲得這百萬美元。問題在于:JavaScript 會假定時區是瀏覽器提供的時區,除非另有明確指定。
這意味著,new Date ("12/20/1989") 將創建一個日期 1989-12-20T00:00:00+5:45 或 1989-12-19T18:15:00Z ,而這與時間戳為 1989-12-20T00:00:00Z 是不同的。
不能只更改現有日期對象的時區,因此現在的目標是創建一個新的日期對象,但使用 UTC 而不是本地時區。
在創建日期對象時將忽略用戶的時區并使用 UTC。有兩種方法可以做到這一點:
根據用戶輸入日期創建 ISO 格式的日期字符串,并使用它創建 Date 對象。 使用有效的 ISO 日期格式創建 Date 對象,同時明確指定使用的是 UTC 而不是本地時區。
const userEnteredDate = "12/20/1989";
const parts = userEnteredDate.split("/");
const userEnteredDateISO = parts[2] + "-" + parts[0] + "-" + parts[1];
const userEnteredDateObj = new Date(userEnteredDateISO + "T00:00:00Z");
const dateFromAPI = new Date("1989-12-20T00:00:00Z");
const result = userEnteredDateObj.getTime() == dateFromAPI.getTime(); // true
如果不指定時間,這也適用,因為默認為午夜(即 00:00:00Z):
const userEnteredDate = new Date("1989-12-20");
const dateFromAPI = new Date("1989-12-20T00:00:00Z");
const result = userEnteredDate.getTime() == dateFromAPI.getTime(); // true
注意,如果向日期構造函數傳遞了正確的 ISO 日期格式 YYYY-MM-DD 的字符串,則它會自動采用 UTC。
JavaScript 提供了一個簡潔的 Date.UTC() 函數,可以使用它來獲取日期的 UTC 時間戳。從日期中提取組件并將它們傳遞給函數。
const userEnteredDate = new Date("12/20/1989");
const userEnteredDateTimeStamp = Date.UTC(userEnteredDate.getFullYear(), userEnteredDate.getMonth(), userEnteredDate.getDate(), 0, 0, 0);
const dateFromAPI = new Date("1989-12-20T00:00:00Z");
const result = userEnteredDateTimeStamp == dateFromAPI.getTime(); // true
日期差異
下面來討論兩個用例:
- 計算兩個日期之間的天數
將兩個日期轉換為 UTC 時間戳,找出以毫秒為單位的差異并找到等效的天數。
const dateFromAPI = "2016-02-10T00:00:00Z";
const now = new Date();
const datefromAPITimeStamp = (new Date(dateFromAPI)).getTime();
const nowTimeStamp = now.getTime();
const microSecondsDiff = Math.abs(datefromAPITimeStamp - nowTimeStamp);
// 使用 Math.round 代替 Math.floor 來考慮某些 DST 情況
// 每天的毫秒數 = 24 小時/天 * 60 分鐘/小時 * 60 秒/分鐘 * 1000 毫秒/秒
const daysDiff = Math.round(microSecondsDiff / (1000 * 60 * 60 * 24));
console.log(daysDiff);
- 根據出生日期計算用戶的年齡
const birthDateFromAPI = "12/10/1989";
日期/時間操作最佳實踐
從用戶獲取日期和時間
如果需要從用戶那里獲取日期和時間,那么很可能需要的是他們的本地日期時間。我們在日期計算部分看到Date構造函數可以接受多種不同的日期格式。
為了消除任何混淆,建議使用new Date(year, month, day, hours, minutes, seconds, milliseconds)格式來創建日期,這是使用Date構造函數時能夠做到的最明確的方式。
可以使用允許省略最后四個參數的變體,如果它們為零;例如,new Date(2012, 10, 12)與new Date(2012, 10, 12, 0, 0, 0, 0)是相同的,因為未指定的參數默認為零。
例如,如果正在使用一個日期和時間選擇器,它給出了日期2012-10-12和時間12:30,可以提取這些部分并創建一個新的Date對象,如下所示:
const datePickerDate = '2012-10-12';
const timePickerTime = '12:30';
const [year, month, day] = datePickerDate.split('-').map(Number);
const [hours, minutes] = timePickerTime.split(':').map(Number);
const dateTime = new Date(year, month - 1, day, hours, minutes);
console.log(dateTime); // Fri Oct 12 2012 12:30:00 GMT+0800 (中國標準時間)
在上述示例中,首先將日期和時間分別存儲在datePickerDate和timePickerTime變量中。然后,使用split()方法將日期字符串和時間字符串拆分為數值數組,并將其存儲在[year, month, day]和[hours, minutes]變量中。最后,使用這些值創建一個新的Date對象,注意按照 JavaScript 的月份規則,需要將月份減去1。這樣就得到了一個包含用戶所選日期和時間的Date對象。
通過遵循這種方法,可以明確地指定日期和時間,以便消除不同日期解析格式可能帶來的混亂。
const dateFromPicker = "2012-10-12";
const timeFromPicker = "12:30";
const dateParts = dateFromPicker.split("-");
const timeParts = timeFromPicker.split(":");
const localDate = new Date(dateParts[0], dateParts[1]-1, dateParts[2], timeParts[0], timeParts[1]);
注意,盡量避免從字符串創建日期,除非它是 ISO 日期格式。 請改用 Date(year, month, date, hours, minutes, seconds, microseconds) 方法。
僅獲取日期
如果只獲取日期(例如用戶的生日),最好將格式轉換為有效的 ISO 日期格式,以消除任何可能導致日期在轉換為 UTC 時向前或向后移動的時區信息。 例如:
const dateFromPicker = "12/20/2012";
const dateParts = dateFromPicker.split("/");
const ISODate = dateParts[2] + "-" + dateParts[0] + "-" + dateParts[1];
const birthDate = new Date(ISODate).toISOString();
如果使用有效的 ISO 日期格式 (YYYY-MM-DD) 輸入創建一個 Date 對象,它將默認為 UTC,而不是默認為瀏覽器的時區。
存儲日期
始終以 UTC 格式存儲日期時間,始終將 ISO 日期字符串或時間戳保存到數據庫。實踐證明,在后端存儲本地時間是一個壞主意,最好讓瀏覽器在前端處理到本地時間的轉換。不應該將“July 20, 1989 12:10 PM”之類的日期時間字符串發送到后端。
可以使用 Date 對象的 toISOString() 或 toJSON() 方法將本地時間轉換為 UTC。
const dateFromUI = "12-13-2012";
const timeFromUI = "10:20";
const dateParts = dateFromUI.split("-");
const timeParts = timeFromUI.split(":");
const date = new Date(dateParts[2], dateParts[0]-1, dateParts[1], timeParts[0], timeParts[1]);
const dateISO = date.toISOString();
$.post("http://example.com/", {date: dateISO}, ...)
顯示日期和時間
- 從 API 獲取時間戳或 ISO 格式的日期。
- 創建一個日期對象。
- 使用 toLocaleString() 或 toLocaleDateString() 和 toLocaleTimeString() 方法或日期庫來顯示本地時間。
const dateFromAPI = "2016-01-02T12:30:00Z";
const localDate = new Date(dateFromAPI);
const localDateString = localDate.toLocaleDateString(undefined, {
day: 'numeric',
month: 'short',
year: 'numeric',
});
const localTimeString = localDate.toLocaleTimeString(undefined, {
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
});
現代日期/時間處理 API:Temporal
JavaScript 中的日期處理 Date() 對象一直是飽受詬病,該對象是1995 年受到 Java 的啟發而實現的,自此就一直沒有改變過。雖然Java已經放棄了這個對象,但是 Date() 仍保留在 JavaScript 中來實現瀏覽器的兼容。
Date() API 存在的問題:
- 只支持UTC和用戶的PC時間;
- 不支持公歷以外的日歷;
- 字符串到日期解析容易出錯;
- Date 對象是可變的,比如:
const today = new Date();
const tomorrow = new Date(today.setDate(today.getDate() + 1));
console.log(tomorrow);
console.log(today);
此時,兩個時間輸出是一樣的,不符合我們的預期。正因為 Date() 對象存在的種種問題。平時我們經常需要借助 moment.js、Day.js等日期庫,但是它們的體積較大,有時一個簡單的日期處理就需要引入一個庫,得不償失。
目前,由于Date API 在很多庫和瀏覽器引擎中的廣泛使用,沒有辦法修復API的不好的部分。而改變Date API 的工作方式也很可能會破壞許多網站和庫。
正因如此,TC39提出了一個全新的用于處理日期和時間的標準對象和函數——Temporal。新的Temporal API 提案旨在解決Date API的問題。它為 JavaScript 日期/時間操作帶來了以下修復:
- 僅可以創建和處理不可變Temporal對象;
- 提供用于日期和時間計算的簡單 API;
- 支持所有時區;
- 從 ISO-8601 格式進行嚴格的日期解析;
- 支持非公歷。
Temporal 將取代 Moment.js 之類的庫,這些庫很好地填補了 JavaScript 中的空白,這種空白非常普遍,因此將功能作為語言的一部分更有意義。
由于該提案還未正式發布,所以,可以借助官方提供的prlyfill來測試。首選進行安裝:
npm install @js-temporal/polyfill
導入并使用:
import { Temporal } from '@js-temporal/polyfill';
console.log(Temporal);
Temporal 對象如下:
下面就來看看 Temporal 對象有哪些實用的功能。
當前時間和日期
Temporal.Now 會返回一個表示當前日期和時間的對象:
// 自1970年1月1日以來的時間(秒和毫秒)
Temporal.Now.instant().epochSeconds;
Temporal.Now.instant().epochMilliseconds;
// 當前位置的時間
Temporal.Now.zonedDateTimeISO();
// 當前時區
Temporal.Now.timeZone();
// 指定時區的當前時間
Temporal.Now.zonedDateTimeISO('Europe/London');
實例時間和日期
Temporal.Instant 根據 ISO 8601 格式的字符串返回一個表示日期和時間的對象,結果會精確到納秒:
Temporal.Instant.from('2022-02-01T05:56:78.999999999+02:00[Europe/Berlin]');
// 輸出結果:2022-02-01T03:57:18.999999999Z
Temporal.Instant.from('2022-02-011T05:06+07:00');
// 輸出結果:2022-01-31T22:06:00Z
除此之外,還可以獲取紀元時間的對應的日期(UTC 1970年1月1日0點是紀元時間):
Temporal.Instant.fromEpochSeconds(1.0e8);
// 輸出結果:1973-03-03T09:46:40Z
時區日期和時間
Temporal.ZonedDateTime 返回一個對象,該對象表示在特定時區的日期/時間:
new Temporal.ZonedDateTime(
1234567890000, // 紀元時間
Temporal.TimeZone.from('Europe/London'), // 時區
Temporal.Calendar.from('iso8601') // 默認日歷
);
Temporal.ZonedDateTime.from('2025-09-05T02:55:00+02:00[Africa/Cairo]');
Temporal.Instant('2022-08-05T20:06:13+05:45').toZonedDateTime('+05:45');
// 輸出結果:
Temporal.ZonedDateTime.from({
timeZone: 'America/New_York',
year: 2025,
month: 2,
day: 28,
hour: 10,
minute: 15,
second: 0,
millisecond: 0,
microsecond: 0,
nanosecond: 0
});
// 輸出結果:2025-02-28T10:15:00-05:00[America/New_York]
簡單的日期和時間
我們并不會總是需要使用精確的時間,因此 Temporal API 提供了獨立于時區的對象。這些可以用于更簡單的活動。
- Temporal.PlainDateTime:指日歷日期和時間。
- Temporal.PlainDate:指特定的日歷日期。
- Temporal.PlainTime:指一天中的特定時間。
- Temporal.PlainYearMonth:指沒有日期成分的日期,例如“2022 年 2 月”。
- Temporal.PlainMonthDay:指沒有年份的日期,例如“10 月 1 日”。
它們都有類似的構造函數,以下有兩種形式來創建簡單的時間和日期:
new Temporal.PlainDateTime(2021, 5, 4, 13, 14, 15);
Temporal.PlainDateTime.from('2021-05-04T13:14:15');
new Temporal.PlainDate(2021, 5, 4);
Temporal.PlainDate.from('2021-05-04');
new Temporal.PlainTime(13, 14, 15);
Temporal.PlainTime.from('13:14:15');
new Temporal.PlainYearMonth(2021, 4);
Temporal.PlainYearMonth.from('2019-04');
new Temporal.PlainMonthDay(3, 14);
Temporal.PlainMonthDay.from('03-14');
日期和時間值
所有 Temporal 對象都可以返回特定的日期/時間值。例如,使用ZonedDateTime:
const t1 = Temporal.ZonedDateTime.from('2025-12-07T03:24:30+02:00[Africa/Cairo]');
t1.year; // 2025
t1.month; // 12
t1.day; // 7
t1.hour; // 3
t1.minute; // 24
t1.second; // 30
t1.millisecond; // 0
t1.microsecond; // 0
t1.nanosecond; // 0
其他有用的屬性包括:
- dayOfWeek(周一為 1 至周日為 7)
- dayOfYear(1 至 365 或 366)
- weekOfYear(1 到 52,有時是 53)
- daysInMonth(28、29、30、31)
- daysInYear(365 或 366)
- inLeapYear(true或false)
比較和排序日期
所有 Temporal 對象都可以使用 compare() 返回整數的函數進行比較。例如,比較兩個ZonedDateTime對象:
Temporal.ZonedDateTime.compare(t1, t2);
這個比較結果會有三種情況:
- 當兩個時間值相等時,返回 0;
- 當 t1 在 t2 之后時,返回 1;
- 當 t1 在 t2 之前時,但會 -1;
const date1 = Temporal.Now,
const date2 = Temporal.PlainDateTime.from('2022-05-01');
Temporal.ZonedDateTime.compare(date1, date2); // -1
compare() 的結果可以用于數組的 sort() 方法來對時間按照升序進行排列(從早到晚):
const t = [
'2022-01-01T00:00:00+00:00[Europe/London]',
'2022-01-01T00:00:00+00:00[Africa/Cairo]',
'2022-01-01T00:00:00+00:00[America/New_York]'
].map(d => Temporal.ZonedDateTime.from(d))
.sort(Temporal.ZonedDateTime.compare);
日期計算
提案還提供了幾種方法來對任何 Temporal 對象執行日期計算。當傳遞一個Temporal.Duration對象時,它們都會返回一個相同類型的新的 Temporal,該對象使用years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds 和 nanoseconds 字段來設置時間。
const t1 = Temporal.ZonedDateTime.from('2022-01-01T00:00:00+00:00[Europe/London]');
t1.add({ hours: 8, minutes: 30 }); // 往后8小時30分
t1.subtract({ days: 5 }); // 往前5天
t1.round({ smallestUnit: 'month' }); // 四舍五入到最近的月份
until() 和 since() 方法會返回一個對象,該 Temporal.Duration 對象描述基于當前日期/時間的特定日期和時間之前或之后的時間,例如:
t1.until().months; // 到t1還有幾個月
t2.until().days; // 到t2還有幾天
t3.since().weeks; // t3已經過去了幾周
equals() 方法用來確定兩個日期/時間值是否相同:
const d1 = Temporal.PlainDate.from('2022-01-31');
const d2 = Temporal.PlainDate.from('2023-01-31');
d1.equals(d2); // false
格式化日期
雖然這不是 Temporal API 的一部分,但 JavaScript Intl(國際化)API提供了一個 DateTimeFormat() 構造函數,可以用于格式化 Temporal 或 Date 對象:
const d = new Temporal.PlainDate(2022, 3, 14);
// 美國日期格式:3/14/2022
new Intl.DateTimeFormat('en-US').format(d);
// 英國日期格式:14/3/2022
new Intl.DateTimeFormat('en-GB').format(d);
// 西班牙長日期格式:miércoles, 14 de abril de 2022
new Intl.DateTimeFormat('es-ES', { dateStyle: 'full' }).format(d);
瀏覽器支持
目前還沒有瀏覽器支持 Temporal API:
Temporal 提案:https://tc39.es/proposal-temporal/。
日期/時間操作庫
在 JavaScript 中進行日期/時間操作是一個很麻煩的事,JS的生態中有很多實用的日期操作庫,最后就來分享幾個實用的日期庫。
Moment.js
Moment.js 是一個輕量級 JavaScript 日期庫,用于解析、驗證、操作和格式化日期,是一個很受歡迎的日期操作庫。
不過,Moment.js 是一個遺留項目,現在處于維護模式。維護者認為,無法重構 Moment.js 來滿足現代 JavaScript 開發的需求,例如不變性和 tree shaking。Lighthouse(Chrome 的內置審核工具)警告不要使用 Moment,因為它的大小較大 (329 kb)。
安裝Moment.js
可以通過以下任一方式來安裝該庫:
npm install moment --save # npm
yarn add moment # Yarn
Install-Package Moment.js # NuGet
spm install moment --save # spm
meteor add momentjs:moment # meteor
導入Moment.js
在 JavaScript 文件中,導入Moment.js庫:
const moment = require('moment');
創建日期對象
可以傳遞一個日期字符串或日期對象給moment()函數,然后返回一個Moment對象:
const date = moment('2023-07-04');
格式化日期顯示
Moment.js 提供了豐富的日期格式化選項。可以使用format()方法將日期格式化為所需的字符串格式:
const formattedDate = date.format('YYYY-MM-DD');
console.log(formattedDate); // 輸出:2023-07-04
日期運算
Moment.js提供了許多方便的方法來進行日期和時間的運算。下面是一些示例:
// 添加一天
const tomorrow = date.add(1, 'day');
console.log(tomorrow.format('YYYY-MM-DD')); // 輸出:2023-07-05
// 減去一個月
const lastMonth = date.subtract(1, 'month');
console.log(lastMonth.format('YYYY-MM-DD')); // 輸出:2023-06-04
// 比較日期
const otherDate = moment('2023-07-10');
console.log(date.isBefore(otherDate)); // 輸出:true
console.log(date.isAfter(otherDate)); // 輸出:false
Moment.js還提供了許多其他常用的功能,如獲取當前日期、解析日期字符串、計算日期之間的差異等。
Date-fns
Date-fns 是一個現代、輕量級的JavaScript日期處理庫,用于在瀏覽器和Node.js環境中處理日期和時間。它的設計目標是提供一組簡單、純函數式的API來執行各種日期操作,而不依賴于全局對象。
以下是Date-fns 的特點:
- 輕量級:Date-fns非常小巧,只包含所需的功能,可以減少項目的文件大小。
- 純函數:Date-fns的函數都是純函數,即相同的輸入總是產生相同的輸出,不存在副作用。這使得代碼更可預測、易測試和可維護。
- 易于使用:Date-fns的API設計簡單易懂,與現代JavaScript的語法和慣用法保持一致。它提供了大量的日期處理功能,如格式化、解析、比較、計算等。
- 兼容性:Date-fns支持所有現代的瀏覽器和Node.js版本。
安裝Date-fns
可以使用npm或yarn等包管理工具來安裝Date-fns。在項目目錄下運行以下命令安裝Date-fns:
npm install date-fns
導入Date-fns
在JavaScript文件中導入所需的Date-fns函數:
import { format, parseISO, differenceInDays } from 'date-fns';
使用Date-fns函數
使用導入的函數來執行各種日期操作。以下是一些示例:
const date = new Date();
// 格式化日期
const formattedDate = format(date, 'yyyy-MM-dd');
console.log(formattedDate); // 輸出:2023-07-04
// 解析日期字符串
const parsedDate = parseISO('2023-07-04');
console.log(parsedDate); // 輸出:Tue Jul 04 2023 00:00:00 GMT+0530 (India Standard Time)
// 計算日期之間的差異
const startDate = new Date(2023, 6, 1);
const endDate = new Date(2023, 6, 10);
const diff = differenceInDays(endDate, startDate);
console.log(diff); // 輸出:9
在上述示例中,使用了format()函數將日期格式化為指定的字符串格式,使用了parseISO()函數解析日期字符串為日期對象,以及使用了differenceInDays()函數計算兩個日期之間的天數差異。
Day.js
Day.js 是一個輕量級的JavaScript日期處理庫,用于解析、操作和格式化日期對象。它的設計目標是提供一個簡單、靈活的API,使得處理日期和時間變得更加方便。
以下是 Day.js 的特點:
- 輕量級:Day.js非常小巧,壓縮后僅有2 KB左右的大小,可以減少項目的文件大小。
- 易用性:Day.js的API設計簡潔明了,與現代JavaScript的語法和慣用法保持一致。你可以輕松地對日期進行解析、格式化、計算、比較等操作。
- 不可變性:Day.js的日期對象是不可變的,即每次對日期進行操作都會返回一個新的日期對象,而不會修改原始對象。這種設計模式有助于避免副作用,并提高代碼的可預測性。
- Moment.js兼容性:Day.js的API設計與Moment.js類似,因此可以很容易地從Moment.js遷移到Day.js,而無需更改太多代碼。
安裝Day.js
可以使用npm或yarn等包管理工具來安裝Day.js。在項目目錄下運行以下命令安裝Day.js:
npm install dayjs
導入Day.js
在JavaScript文件中導入Day.js:
import dayjs from 'dayjs';
使用Day.js函數
使用Day.js的函數來進行日期操作。以下是一些示例:
const date = dayjs();
// 格式化日期
const formattedDate = date.format('YYYY-MM-DD');
console.log(formattedDate); // 輸出:2023-07-04
// 解析日期字符串
const parsedDate = dayjs('2023-07-04');
console.log(parsedDate); // 輸出:Tue Jul 04 2023 00:00:00 GMT+0530 (India Standard Time)
// 計算日期之間的差異
const startDate = dayjs('2023-07-01');
const endDate = dayjs('2023-07-10');
const diff = endDate.diff(startDate, 'day');
console.log(diff); // 輸出:9
在上述示例中,使用了format()函數將日期格式化為指定的字符串格式,使用了dayjs()函數解析日期字符串為日期對象,以及使用了diff()函數計算兩個日期之間的天數差異。
Luxon
Luxon 是一個用于處理日期、時間和時區的先進 JavaScript 庫。它提供了一組強大的功能,可以幫助你在瀏覽器和 Node.js 環境中輕松處理日期和時間。
以下是 Luxon 的特點:
- 強大的日期和時間處理:Luxon 提供了豐富的 API,用于解析、格式化、操作和比較日期和時間。它支持多種標準和自定義的日期和時間格式,包括 ISO 8601、RFC 2822 等。
- 支持時區處理:Luxon 支持全球各地的時區,并提供了靈活的時區轉換功能。它使用 IANA(Olson)時區數據庫,確保準確的時區信息。
- 不可變性:Luxon 的日期對象是不可變的,每次對日期進行操作都會返回一個新的日期對象,而不會修改原始對象。這種設計模式有助于避免副作用,并提高代碼的可預測性。
- 鏈式調用:Luxon 的 API 允許你使用鏈式調用,使得代碼更簡潔、易讀。你可以按順序執行多個操作,而無需多次引用日期對象。
安裝 Luxon
使用 npm 或 yarn 等包管理工具,在項目目錄下運行以下命令安裝 Luxon:
npm install luxon
導入 Luxon
在 JavaScript 文件中導入 Luxon:
import { DateTime } from 'luxon';
使用 Luxon 函數
使用 Luxon 的函數來處理日期和時間。以下是一些示例:
const now = DateTime.now();
// 格式化日期
const formattedDate = now.toFormat('yyyy-MM-dd');
console.log(formattedDate); // 輸出:2023-07-04
// 解析日期字符串
const parsedDate = DateTime.fromISO('2023-07-04');
console.log(parsedDate); // 輸出:DateTime { ... }
// 計算日期之間的差異
const startDate = DateTime.fromISO('2023-07-01');
const endDate = DateTime.fromISO('2023-07-10');
const diff = endDate.diff(startDate, 'days').toObject().days;
console.log(diff); // 輸出:9
在上述示例中,使用了 toFormat() 函數將日期格式化為指定的字符串格式,使用了 fromISO() 函數解析 ISO 8601 格式的日期字符串為日期對象,以及使用了 diff() 函數計算兩個日期之間的天數差異。