Day.js 計算最近7天、上週、上個月的日期

/

2021.04.28 公告:
今天有一位 Andrew 大大留言,內容是用 day.js 取得上個月第一日、最後一日的更簡單的方法,更新在最後一段中。

本篇要解決的問題

最近收到一個設計,是一個跑報表的頁面,設計上放了一個像 GA 選日期的方式,可以讓使用者選擇看上週、上個月、最近 7 天、最近 30 天,因為是用 API 在取資料,因此必須要能在前端就先算出這些日期丟給 API。

之前在 Moment.js 上看見不再更新的公告,裡面有推薦可以改用 Day.js,進到 Day.js 的頁面第一句話就寫著:

Fast 2kB alternative to Moment.js with the same modern API

看到只有 2KB,用就對了!

不過,Day.js 的文件蠻簡潔的,而且沒有一個直接可以算出上個月的功能,本篇就是整理了一下算出前 x 天、上週、上個月的程式碼,也有在專案中實際使用。

以下因為是以「今天」當作基準,這邊先列出今天的日期:2021/03/15。


計算前 7 天

文件:https://day.js.org/docs/en/manipulate/subtract

要計算前幾天的日期方式是一樣的:

var day = dayjs().subtract(7, 'day').format();
console.log(day); // 2021-03-08T21:55:52+08:00

subtract 是指今天開始減去幾天的意思,因此數字寫幾天,就是抓幾天前的日期,1 就是昨天、7 就是前 7 天、30 就是前 30 天。

day 也可以替換成 month, year。

var month = dayjs().subtract(1, 'month').format();
console.log(month); // 2021-02-15T21:56:28+08:00

var year = dayjs().subtract(1, 'year').format();
console.log(year); // 2020-03-15T21:56:28+08:00

計算上週

文件:https://day.js.org/docs/en/plugin/weekdayhttps://day.js.org/docs/en/plugin/loading-into-browser

計算上週,指的是計算出上個禮拜的周一到周日。

這是廣告,點擊一下可以幫本站多個一點點的廣告收入,謝謝

如果要使用 weekday 的功能,要另外裝上外掛,這邊用引用 CDN 的方式做示範:

<script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.10.4/dayjs.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.10.4/plugin/weekday.min.js"></script>
<script>
  dayjs.extend(window.dayjs_plugin_weekday);
	
  // 以下是上一個周一 ~ 周日
  var mon = dayjs().weekday(-6).format(); // 2021-03-08T21:57:37+08:00
  var tue = dayjs().weekday(-5).format(); // 2021-03-09T21:57:37+08:00
  var wen = dayjs().weekday(-4).format(); // 2021-03-10T21:57:37+08:00
  var thu = dayjs().weekday(-3).format(); // 2021-03-11T21:57:37+08:00
  var fri = dayjs().weekday(-2).format(); // 2021-03-12T21:57:37+08:00
  var sat = dayjs().weekday(-1).format(); // 2021-03-13T21:57:37+08:00
  var sun = dayjs().weekday(0).format(); // 2021-03-14T21:57:37+08:00
</script>

除了計算上週,也可以拿來計算本週、下週,數字就繼續往下算:

本週

var mon = dayjs().weekday(1).format();
var tue = dayjs().weekday(2).format();
var wen = dayjs().weekday(3).format();
var thu = dayjs().weekday(4).format();
var fri = dayjs().weekday(5).format();
var sat = dayjs().weekday(6).format();
var sun = dayjs().weekday(7).format();

下週

var mon = dayjs().weekday(8).format();
var tue = dayjs().weekday(9).format();
var wen = dayjs().weekday(10).format();
var thu = dayjs().weekday(11).format();
var fri = dayjs().weekday(12).format();
var sat = dayjs().weekday(13).format();
var sun = dayjs().weekday(14).format();

計算上個月

文件:https://day.js.org/docs/en/get-set/date

本月是 3 月,上個月指的就是 2/1 – 2/28。

Day.js 有提供抓出一個月中第幾天的日期:

dayjs().date(1);

上面這行會吐出本月的第一天,但有個問題,4 月只有 30 天,沒有 31 天,如果我們寫了 31,那多出來的一天就會給 5/1,而不會自動停在那個月份的最大天數。

另外計算月份這件事也有天然的麻煩:

這是廣告,點擊一下可以幫本站多個一點點的廣告收入,謝謝

  • 2 月有閏年(28 天或 29 天)
  • 如果本月是 1 月,那上個月就會是「去年」的 12 月
  • 小月有 30 天,大月是 31 天

第 2 個跨年度的問題好解決,就判斷這個月是 1 月的話把今年的年份 -1。

第 3 個問題也好解決,就判斷是哪些月份,遇到那些月份就設成 31 天,其它不是 2 月的話就設 30 天。

麻煩的是閏年。

處理閏年

有句話說 Google 是父,維基是母,或是直接說維基就是轉機。

如果直接找「閏年」的維基百科,會發現上面有寫出判斷閏年的方式:

被 4 整除且不被 100 整除 或 被 400 整除

所以在判斷上我們只需要寫:

var currentYear = dayjs().year(); // 本年
let monthMaxDay; // 放 28 天或 29 天

if(currentYear % 4 === 0 &amp;&amp; currentYear % 100 !== 0 || currentYear % 400 === 0) {
  monthMaxDay = 29;
} else {
  monthMaxDay = 28;
}

30 天、31 天

最快的判斷方式,就是把所有 31 天的月份存在陣列裡,如果上個月的月份是在這陣列中,就給 31 天,不在陣列中就給 30 天,當然,在這之前記得先判斷完 2 月。

// 本月,dayjs 的月份值是「該月 - 1」,因此要 +1 回來
var currentMonth = dayjs().month() + 1;

// 本月如果是 1 月,上個月就要是 12 月,並且年份減 1
var lastMonth;
if(currentMonth === 1) {
  lastMonth = 12;
  currentYear -= 1;
} else {
  lastMonth = currentMonth - 1;
}

// 1, 3, 5, 7, 8, 10, 12 為大月
var bigMonth = [1, 3, 5, 7, 8, 10, 12];

// 不是 31 天,就是 30 天
let monthMaxDay; // 放 30 天或 31 天

// 上一個月如果有在陣列中,就是 31 天,否則就是 30 天
if(bigMonth.includes(lastMonth)) {
  monthMaxDay = 31;
} else {
  monthMaxDay = 30;
}

完整判斷「上個月」程式碼

Andrew 大大提供的方法


以上是 Augustus 研究出的方法,如果各位大大們有更簡單的方式還請留言告知~

Summary
Day.js 計算最近7天、上週、上個月的日期
Article Name
Day.js 計算最近7天、上週、上個月的日期
Description
本篇大綱:本篇要解決的問題。計算前 7 天。計算上週。計算上個月。處理閏年。30 天、31 天。完整判斷「上個月」程式碼。Day.js 的文件蠻簡潔的,而且沒有一個直接可以算出上個月的功能,本篇就是整理了一下算出前 x 天、上週、上個月的程式碼,也有在專案中實際使用。
Augustus
Let's Write
Let's Write
https://letswrite.tw/wp-content/uploads/2020/08/logo_512.jpg

隨選筆記文

Bot Telegram

Telegram Bot 學習筆記 – 2:用 Google Apps Script 接收 / 推播訊息

Vue

Vue.js 用 computed 跟 filter 做一個簡易搜尋功能

Analytics Google

GA:啟用 Web + APP 報表

Front-End

用 JavaScript 將 JSON 轉為 CSV 檔下載

Front-End

拿 Trello 當資料庫 建一個店家清單 – 上篇:Trello 基本使用

API

Instagram Embedding 抓 iframe 高度及 3 種大小圖片

Bot Telegram

Telegram Bot 學習筆記 – 3:鍵盤 keyboard

WordPress

WordPress SEO 有幫助的 2 個外掛

API

GitHub API:建立 Issue、Comment – API、Personal access tokens

Front-End

MacBook 用隨身碟執行 Windows 10:Windows To Go、WinToUSB

以下是留言,但關於留言的部份必需先讓你們知道:

本站的文章都是 Augustus 因為覺得有趣,才會實作並整理成筆記文而後進行發表。

如果留言是希望把 Demo 改成「你想要」的樣子,或是把功能改成「符合你需求」的樣子,

Sorry~ 除非那修改是 Augustus 也有興趣的,不然不會幫你們寫程式去面對工作或是交作業。

未來這類的留言不會再主動回覆。😎

另外,公開信箱是為了讓金流驗證用,

因為之前遇過幾次回信協助解決問題後,對方卻一聲謝謝也沒有,就這樣拿去幫工作交差。

因此決定不再回覆信件,有疑問就利用留言功能囉。

訂閱
通知
guest
4 Comments
最舊
最新
Inline Feedbacks
看所有留言
Denny
Denny
3 月 之前

取得上個月的起訖日期,可以試試這樣寫法 (但我沒做過完整測試…)

使用 day.js

let today = dayjs(); // 當日
// let today = dayjs(new Date(2021, 2, 15)); // 若要測試 3 月份的前一月份

// 上月第一天
console.log(
  today.date(1).subtract(1, 'month').format('YYYY-MM-DD')
);
// 或是
console.log(
  today.date(1).subtract(1, 'month').hour(0).minute(0).second(0).format()
);


// 上月最後一天
console.log(
  today.date(0).format('YYYY-MM-DD')
);

// 或是
console.log(
  today.date(0).hour(0).minute(0).second(0).format()
);

「不」使用依賴的話

let now = new Date(); // 當日
// let now = new Date(2021, 2, 15); // 若要測試 3 月份的前一月份

// 上月第一天
console.log(
  new Date(now.getFullYear(), now.getMonth() - 1, 1).toLocaleDateString()
);

// 上月最後一天
console.log(
  new Date(now.getFullYear(), now.getMonth(), 0).toLocaleDateString()
);
Last edited 3 月 之前 by Denny
andrew
andrew
3 月 之前

上個月的起訖 , 我會用 startOfendOf

// 上個月第一天
 dayjs().subtract(1, 'month').startOf('month').toDate();

// 上個月最後一天
 dayjs().subtract(1, 'month').endOf('month').toDate();

如果需要 timezone +0 的上個月起迄 , 我會使用 utc

// 上個月第一天 ( 格林威治時間 )
dayjs().utc().subtract(1, 'month').startOf('month').toDate();
Last edited 3 月 之前 by andrew

Let's Write

前端工程師 Augustus 的學習筆記 — solving problems, in simple ways.