請啟用 Javascript 查看內容

日期時間

 ·  ☕ 10 分鐘

JavaScript筆記 目錄

2021.03.31 更新

Date 物件

JavaScript 沒有日期資料型別,但它有內建物件 Date 物件,可以用來處理日期與時間。Date 物件是以世界標準時間(UTC) 1970 年 1 月 1 日為零點,範圍為前後各 1 億天(+-100,000,000),單位為毫秒(ms)。

Date 物件只能由 new Date() 作為建構器來產生,不帶參數使用將會建立當前時間的 Date 物件:

1
const date = new Date();

Date 實體求值時,與其他物件預設呼叫 valueOf 方法不同,它預設會呼叫 toString 方法,因此求值時會回傳完整日期時間格式的字串:

1
2
3
4
5
6
7
// 承接上段程式碼

console.log(date);
// 等同於
console.log(date.toString());

// "Sun Mar 28 2021 14:12:01 GMT+0800 (台北標準時間)"

若是作為普通函式直接呼叫 Date,會回傳完整日期時間格式的字串,而非 Date 物件,無法使用 Date 物件方法:

1
2
console.log(Date());
// "Sun Mar 28 2021 14:12:01 GMT+0800 (台北標準時間)"

CodePen Demo:JavaScript 日期時間 - Date 物件

基礎概念

1. 時間標準

由於地球自轉是稍微不規則的(緩慢減速),因此格林威治標準時間已經被原子鐘報時的世界協調時間所取代。但 GMT 和 UTC 在一般使用的情況下(不需要非常精確的情況)並沒有差異,所以通常將 GMT 和 UTC 視為等同,舉例來說:台灣時區可以標示為 GMT+8 或 UTC+8 。

2. 時區

時區 是地球上的區域使用同一個時間定義。

  • 時差,世界各國位於地球不同位置上,因此不同國家,特別是東西跨度大的國家日出、日落時間必定有所偏差。這些偏差就是所謂的時差。
  • 偏移(offset),指的是某地區與 GTM/UTC 偏移的時間,例如 +08:00 表示該地區的時間比 GTM/UTC 快了 8 小時。
  • 理論時區,指的是以被 15 整除的經線為中心,向東西兩側延伸 7.5°,即每 15° 劃分一個時區。
  • 法定時區,指的是為了避開國界線,有的時區的形狀並不規則,而且比較大的國家以國家內部行政分界線為時區界線,這是實際時區。
  • 夏令時間(Daylight Saving Time, DST),指的是一種在夏季將時間調快一小時的做法。

建立 Date 物件

new Date() 語法基本為四種形式的參數:

  1. 空值(不帶參數)
  2. 毫秒
  3. 日期時間字串
  4. 時間單位
1
2
3
4
new Date();
new Date(milliseconds);
new Date(dateString);
new Date(year, monthIndex [, day [, hours [, minutes [, seconds [, milliseconds]]]]]);

1. 不帶參數

new Date() 不帶參數,表示當前日期時間的 Date 物件。

1
2
3
const now = new Date();
console.log(now);
// "Sun Mar 28 2021 17:50:30 GMT+0800 (台北標準時間)"

2. 毫秒

new Date(milliseconds)milliseconds 表示從 1970-01-01 00:00:00 UTC+0 開始所經過的毫秒數。

1
2
3
const date = new Date(0);
console.log(date);
// "Thu Jan 01 1970 08:00:00 GMT+0800 (台北標準時間)"

經過一百天:

1
2
3
4
5
const dayms = 24 * 60 * 60 * 1000;
const d100 = new Date(dayms * 100);

console.log(d100);
// "Sat Apr 11 1970 08:00:00 GMT+0800 (台北標準時間)"

3. 日期時間字串

new Date(datestring)datestring 表示一個日期或時間格式的字串,該參數會通過 Date.parse 算法解析字串。

日期時間格式字串定義(ISO8601):

YYYY-MM-DDTHH:mm:ss.sssZ
  • 日期 YYYY-MM-DD年-月-日
  • 字串 T:是一個分隔符號
  • 時間 HH:mm:ss.sss小時:分鐘:秒.毫秒
  • 時區:UTC+8 使用 +08:00 表示,若時區為 UTC+0 可使用 Z 表示。
1
2
3
4
5
6
7
const d1 = new Date('2021-03-28T10:30:55.000Z');
console.log(d1);
// "Sun Mar 28 2021 18:30:55 GMT+0800 (台北標準時間)"

const d2 = new Date('2021-03-28T10:30:55.000+08:00'); 
console.log(d2);
// "Sun Mar 28 2021 10:30:55 GMT+0800 (台北標準時間)"

:::warning
若輸入非標準日期字串,會根據各家瀏覽器的實現方式,而有不同的結果。詳細可以參考 MDN 說明。
:::

:::warning
另外要注意,Date 物件在建立時,會將日期時間轉成本地時區(作業系統設定的時區)輸出,並不支持指定時區輸出。
:::

4. 時間單位

new Date(year, month, [date, hours, minutes, seconds, ms])

  • 必要參數:年、月
    • 年(必須是四位數)
    • 0 ~ 11
  • 選擇性的參數:日、時、分、秒、毫秒
    • 日(預設為 1
    • 時、分、秒、毫秒(預設為 0

預設的時區為本地時區(作業系統設定的時區):

1
2
3
const d2021 = new Date(2021, 0);
console.log(d2021);
// "Fri Jan 01 2021 00:00:00 GMT+0800 (台北標準時間)"

如果超出正確範圍內的數字會自動轉換成對應時間:

1
2
3
const date = new Date(2021, 12);
console.log(date);
// "Sat Jan 01 2022 00:00:00 GMT+0800 (台北標準時間)"

獲取 & 設定

1. 獲取

從 Date 物件取的相對應的時間數值(number),可以使用 Date 提供的方法:

以上所有的方法回傳的訊息都是基於當地時區的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
function getDate(date) {
  return {
    year: date.getFullYear(),
    month: date.getMonth(),
    date: date.getDate(),
    hour: date.getHours(),
    min: date.getMinutes(),
    sec: date.getSeconds(),
    msec: date.getMilliseconds(),
    day: date.getDay(),
  };
}

如果要獲取標準時間,則可以使用對應的 UTC 版本,例如 getUTCFullYear()getUTCMonth() 等等。

2. 設定

以下方法可以設置時間訊息:

以上方法會回傳改變後的時間戳,另外,也都有對應的 UTC 版本,例如 setUTCHours()

3. 結合使用

兩者方法結合使用,可以得到相對時間:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const date = new Date();

// 將日期向後推1000天
date.setDate(date.getDate() + 1000);

// 將時間設為6小時後
date.setHours(date.getHours() + 6);

// 將年份設為去年
date.setFullYear(date.getFullYear() - 1);

時間戳(Timestamp)

時間戳(Timestamp)指的是從 1970-1-1 00:00:00 UTC+0 開始的毫秒數。

1. 靜態方法

Date 的靜態方法:

  • Date.now():回傳當前時間的數值時間戳。
  • Date.parse():解析日期或時間格式的字串,回傳該時間的數值時間戳(由於瀏覽器之間的不同與差異,不建議使用)。
  • Date.UTC():需要傳入與建構器相同的參數(即年月日等等參數),回傳該時間的數值時間戳。
1
2
3
4
5
6
7
const ms = Date.now();
console.log(ms);
// 1616939369617

const date = new Date(ms);
console.log(date);
// "Sun Mar 28 2021 21:49:29 GMT+0800 (台北標準時間)"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const ms = Date.UTC(2021, 0);
console.log(ms);
// 1609459200000

const date = new Date(ms);
console.log(date);
// "Fri Jan 01 2021 08:00:00 GMT+0800 (台北標準時間)"

console.log(new Date(2021, 0));
// "Fri Jan 01 2021 00:00:00 GMT+0800 (台北標準時間)"

:::warning
輸入的參數會視為世界標準時間,而非本地時間,與建構器不同。
:::

2. 時間戳轉換

Date 物件轉時間戳的方法:

1
2
3
4
5
6
7
8
9
const time = new Date(2021, 0);
console.log(time.getTime());
// 1609430400000

// 等同
console.log(time.valueOf());
// 1609430400000
console.log(Number(time));
// 1609430400000

如果將 Date 物件轉成數值(呼叫 valueOf()),相當於 getTime() 方法。

1. Unix 時間戳

一般來說,後端給的時間會是以秒為單位的 Unix 時間戳,但 JavaScript 的時間戳單位為毫秒。

如果我們有一個 Unix 時間戳,可以透過乘 1000 取得 Date 物件:

1
2
3
4
const unixtimestamp = 1609430400;
const date = new Date(unixtimestamp * 1000);
console.log(date);
// "Fri Jan 01 2021 00:00:00 GMT+0800 (台北標準時間)"

反之,如果要將時間戳轉 Unix 時間戳 就是除 1000:

1
2
3
4
const timestamp = Date.now();
const unixtimestamp = Math.floor(timestamp / 1000);
console.log(unixtimestamp);
// 1616940562

運算

如果對 Date 物件進行減法運算,會自動轉換成對應的毫秒數:

1
2
3
4
const d1 = new Date(2021, 2, 1);
const d2 = new Date(2021, 3, 1);
console.log(d2 - d1);
// 2678400000

若是加法運算則是字串連接:

1
2
3
4
// 承接上段程式碼

console.log(d2 + d1);
// "Thu Apr 01 2021 00:00:00 GMT+0800 (台北標準時間)Mon Mar 01 2021 00:00:00 GMT+0800 (台北標準時間)"

因此我們可以先將時間轉換成成毫秒,再進行運算:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const sec = 1000;
const min = sec * 60;
const hour = min * 60;

let date = new Date(2021, 0, 2);
console.log(date);
// "Sat Jan 02 2021 00:00:00 GMT+0800 (台北標準時間)"

date = new Date(date - hour * 10);
console.log(date);
// "Fri Jan 01 2021 14:00:00 GMT+0800 (台北標準時間)"

減法運算可以直接相減,但加法運算必須使用 getTime() 轉毫秒再運算:

1
2
3
4
5
// 承接上段程式碼

date = new Date(date.getTime() + hour * 10);
console.log(date);
// "Sat Jan 02 2021 00:00:00 GMT+0800 (台北標準時間)"

轉換格式

1. 基本格式字串

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
const date = new Date(2021, 0, 1);

console.log(date.toString());
// "Fri Jan 01 2021 00:00:00 GMT+0800 (台北標準時間)"
console.log(date.toUTCString());
// "Thu, 31 Dec 2020 16:00:00 GMT"
console.log(date.toISOString());
// "2020-12-31T16:00:00.000Z"
console.log(date.toJSON());
// "2020-12-31T16:00:00.000Z
console.log(date.toDateString());
// "Fri Jan 01 2021"
console.log(date.toTimeString());
// "00:00:00 GMT+0800 (台北標準時間)"

2. 本地格式字串

本地格式字串,會因不同語言而有不同的輸出格式:

1
2
3
4
5
6
7
8
const date = new Date(2021, 0, 1);

console.log(date.toLocaleString());
// "2021/1/1 上午12:00:00"
console.log(date.toLocaleDateString());
// "2021/1/1"
console.log(date.toLocaleTimeString());
// "上午12:00:00"

3. 本地格式參數

上述三個本地格式字串方法都有兩個可選的參數:

1
2
3
date.toLocaleString([locales[, options]]);
date.toLocaleDateString([locales[, options]]);
date.toLocaleTimeString([locales[, options]]);
  • locales:字串,指定所用語言。值可參考 地區設定 - 列表,中文為 "zh"、台灣為 "zh-TW"
  • options:選項物件,設定格式化規則。

詳細用法可以參考 Natively Format JavaScript Dates and Times 文章。

第三方函式庫

1. Moment.js

Moment.js 是處理 JavaScript 日期時間熱門函式庫。

不過,官方已宣佈停止開發,進入維護狀態,官方公告

官方總結了兩大問題:

  1. Moment 物件是可變物件;
  2. 體積過大。

替代方案:

  1. 使用 Date 物件 + Intl API 即可。
  2. 改用 Day.js 函式庫,體積小、API 設計與 Moment.js 相同。

2. Day.js

Day.js 函式庫是 Moment.js 輕量化替代方案,API 設計與 Moment.js 相同。

Day.js 沒有對 Date.prototype 做任何修改,而是對 Date 物件做了一層封裝。Day.js 物件是不可變的,所有的 API 操作都將回傳一個全新的實體,避免修改到原始資料。

Day.js

1. 解析

呼叫 dayjs(),建立 Day.js 物件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 當前時間
dayjs(); // 等同 dayjs(new Date()), dayjs(undefined)

// ISO 8601 格式字串
dayjs('2018-04-04T16:00:00.000Z');

// 時間戳
dayjs(1318781876406);

// Unix 時間戳
dayjs.unix(1318781876);

// Date 物件
dayjs(new Date(2018, 8, 18));

// 複製 使用 clone(),或傳入 Day.js 物件
const d1 = dayjs();

const d2 = d1.clone();
const d3 = dayjs(d1);

// 驗證是否為有校時間,回傳 boolean
dayjs().isValid();

2. 獲取 & 設置

不傳參數為 getter、傳參數為 setter,取得的值為本地時間:

1
2
const date = dayjs(0).hour(12);
console.log(date.hour());  // 12

另外,還有 getset 方法,可傳入單位字串:

單位字串 縮寫 說明
date D 月份裡的日期
day d 星期幾(0 ~ 6
month M 月份(0 ~ 11
year y 年份
hour h 小時
minute m 分鐘
second s
millisecond ms 毫秒
1
2
const date = dayjs(0).set('year', 2021);
console.log(date.get('year'));  // 2021

3. 操作

Day.js 支持像這樣的鏈式呼叫一些方法來操作 Day.js 物件。

加減操作:

單位字串 縮寫 說明
day d 星期幾(0 ~ 6
week w
month M 月份(0 ~ 11
year y 年份
hour h 小時
minute m 分鐘
second s
millisecond ms 毫秒
1
2
3
const date = dayjs(0).add(1, 'day');
console.log(date.$d);
// "Fri Jan 02 1970 08:00:00 GMT+0800 (台北標準時間)"

時間開頭、末尾操作:

單位字串 縮寫 說明
year y 今年一月一日零時
month M 本月一日零時
week w 當周第一日零時
day d 當日零時
date d 當日零時
hour h 當前時間零分零秒零毫秒
minute m 當前時間零秒零毫秒
second s 當前時間零毫秒

末尾則相反。

1
2
3
4
5
6
7
8
const date = dayjs();
console.log(date.$d);
// "Mon Mar 29 2021 23:49:30 GMT+0800 (台北標準時間)"

console.log(date.startOf('month').$d);
// "Mon Mar 01 2021 00:00:00 GMT+0800 (台北標準時間)"
console.log(date.endOf('month').$d);
// "Wed Mar 31 2021 23:59:59 GMT+0800 (台北標準時間)"

4. 顯示

呈現 Day.js 物件的方法。

格式化 format()

佔位符號 輸出 說明
YY 18 兩位數的年份
YYYY 2018 四位數的年份
M 1-12 月份,從 1 開始
MM 01-12 月份,兩位數
MMM Jan-Dec 縮寫的月份名稱
MMMM January-December 完整的月份名稱
D 1-31 月份裡的一天
DD 01-31 月份裡的一天,兩位數
d 0-6 一週中的一天,星期天是 0
dd Su-Sa 最簡寫的星期幾
ddd Sun-Sat 簡寫的星期幾
dddd Sunday-Saturday 星期幾
H 0-23 小時
HH 00-23 小時,兩位數
h 1-12 小時, 12 小時制
hh 01-12 小時, 12 小時制,兩位數
m 0-59 分鐘
mm 00-59 分鐘,兩位數
s 0-59
ss 00-59 秒 兩位數
SSS 000-999 毫秒 三位數
Z +05:00 UTC 的偏移量,±HH:mm
ZZ +0500 UTC 的偏移量,±HHmm
A AM PM
a am pm
1
2
3
4
5
6
7
8
const date = dayjs();
console.log(date.$d);
// "Tue Mar 30 2021 00:14:21 GMT+0800 (台北標準時間)"

console.log(date.format('YYYY/MM/DD HH:mm'));
// "2021/03/30 00:14"
console.log(date.format('YY-M-D dddd'));
// "21-3-30 Tuesday"

時間差 diff()

1
2
3
const date1 = dayjs('2019-01-25');
const date2 = dayjs('2018-06-05');
console.log(date1.diff(date2)); // 20217600000

預設單位是毫秒,第二個參數可更改單位(預設取整數),第三參數可以取得浮點數:

1
2
3
4
// 承接上段程式碼

console.log(date1.diff(date2, 'month')); // 7
console.log(date1.diff(date2, 'month', true)); // 7.645161290322581

取得實體時間戳:

1
2
3
4
5
const t1 = dayjs('2019-01-25').valueOf();
const t2 = +dayjs('2019-01-25');

console.log(t1); // 1548345600000
console.log(t2); // 1548345600000

取得實體 Unix 時間戳:

1
2
const t = dayjs('2019-01-25').unix();
console.log(t); // 1548345600

取得當月份天數:

1
dayjs().daysInMonth();

取得原生 Date 物件:

1
dayjs().toDate();

取得日期時間字串:

1
2
3
4
5
6
// 完整格式
dayjs().toString();

// ISO 8601 格式
dayjs().toJSON();
dayjs().toISOString();

5. 查詢

Day.js 物件的查詢方法。

比較:

回傳 Boolean,第二參數可選,指定比較單位。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const date1 = dayjs('2021-01-01');
const date2 = dayjs('2021-08-01');

console.log(date1.isBefore(date2)); // true
console.log(date1.isAfter(date2));  // false
console.log(date1.isSame(date2));   // false

console.log(date1.isBefore(date2, 'year')); // false
console.log(date1.isAfter(date2, 'year'));  // false
console.log(date1.isSame(date2, 'year'));   // true

dayjs.isDayjs() 可以判斷是否為 Day.js 物件:

1
2
3
4
dayjs.isDayjs(dayjs());

// 等同使用 instanceof
dayjs() instanceof dayjs;

6. 國際化 i18n

Day.js 完美支持國際化,但需要加載,支持語言列表可以參考 locale 資料夾

詳細可以參考 官方文件 說明。


竹白
作者
竹白
前端筆記

文章目錄