繼之前文章有提到如何判斷月底是哪一天,我們來解這個練習題吧~
一樣我們透過let()
自定義名稱,簡化公式複雜的撰寫。若要判斷標籤內容對應的狀態,我們可以使用contains()
與ifs()
編輯公式。
當確認公式編輯無誤後,再開一個List View
,使用篩選器功能,當提醒的欄位為True
時就顯示。
lets(
本月第一天, dateSubtract(now(), date(now()) - 1, "days"),
次月第一天, dateAdd(本月第一天, 1, "months"),
月底, date(dateSubtract(次月第一天, 1, "days")),
ifs(
contains(prop("頻率"), "每天"), true,
contains(prop("頻率"), formatDate(now(), "ddd")), true,
contains(prop("頻率"), date(now())), true,
contains(prop("頻率"), 月底), if(月底 == date(now()), true, false),
false
)
)
P.S. 如果你對處理例行公事的設計有興趣,我還準備了一個進階功能的免費模板,詳情可參考 👉 〈Notion 模板 § 例行公事〉。這個模板能透過觸發器設定,讓當日完成的例行公事自動從列表中隱藏,保持列表的清爽與井然有序。
如果你已有想法,不妨自行設計!但若想省時,也可以直接前往〈Notion 模板 § 例行公事〉複製這個模板,輕鬆、快速套用到你的系統中。
我曾經寫過一篇文章〈Notion日期相關公式_工作日計算〉,如同之前文章提到的,已經有支援避開周末的小功能(Avoid weekends),但基於我們需要練習,還是來嘗試把這個公式改成 2.0 的模式。
工作日定義:相對於周末和國定假日,工作日通常是一周中的五天。之前的文章沒有談到如何排除國定假日,今天我們來挑戰加入其他假期的概念,看看如何進行計算。
不過,任何事情都需要循序漸進,所以先來個簡單版的工作日計算吧。
/* 總天數 */
dateBetween(dateEnd(prop("日期時間")), dateStart(prop("日期時間")), "days") + 1
/* 總週數 */
dateBetween(dateEnd(prop("日期時間")), dateStart(prop("日期時間")), "weeks") + 1
如何計算日期區間內的周末天數,這是整個公式中較具挑戰的部分,我們將分為兩個部分來討論。
若是比較簡單的情境,日期區間跨過一個完整周末(即兩天的非工作日),我們可以直接使用「週數」進行計算,只需計算總週數並乘以二即可。但有可能的狀況是,我們的日期區間只佔了周末的一天,就無法使用簡單的方式計算了。 由於計算時總天數
和總週數
都需要在公式中+1
,我特別命名了區間天數
和區間週數
,以便後續計算更加方便。
/* 解釋使用,若要使用請補滿公式內容 */
lets(
開始日期, prop("日期時間").dateStart(),
結束日期, prop("日期時間").dateEnd(),
開始日期_周幾, prop("日期時間").dateStart().day(),
....
區間周數, dateBetween(結束日期, 開始日期, "weeks"),
周末天數, 區間周數 * 2,
......
)
我想僅用公式說明。可能比較難想像,這裡舉個具體的例子。若我們的專案時間是 2024-10-09
到 2024-10-26
,總天數是 18 天,工作天是 13 天。
若我們以總週數 × 2
(3 × 2 = 6)計算周末天數,結果會是錯誤的。正確的算法應該是區間週數 × 2
(2 × 2 = 4),再加上剩餘的周末天數。
(當然你也可以使用總周數-1
的方式,根據個人的習慣選擇。)
接下來我們來討論比較複雜的部分 — 如何計算剩餘的周末天數。
開始日期_周幾 + 區間天數 % 7
:計算從開始日期到區間結束時,剩餘的天數落在一周的周幾。區間天數 % 7
計算的是不足一週的天數。5
:這是用來判斷剩餘天數中是否跨過了週五,超過5
表示有跨到周末(周六、周日)。max(..., 0)
和min(..., 2)
lets(
......
剩餘周末天數, min(max(開始日期_周幾 + 區間天數 % 7 - 5, 0), 2),
......
)
lets(
開始日期, prop("日期時間").dateStart(),
結束日期, prop("日期時間").dateEnd(),
開始日期_周幾, prop("日期時間").dateStart().day(),
區間天數, dateBetween(結束日期, 開始日期, "days"),
總天數, 區間天數 + 1,
區間周數, dateBetween(結束日期, 開始日期, "weeks"),
周末天數, 區間周數 * 2,
剩餘周末天數, min(max(開始日期_周幾 + 區間天數 % 7 - 5, 0), 2),
總天數 - (周末天數 + 剩餘周末天數)
)
若要加入國定假日或是一些特殊節日時,我們可以開另一個資料庫來管理這些節日,之後用匹配資料的方式判斷。
記得所有的國定假日要關聯每一個專案,這樣以後就可以自動化判斷了。
設置的方法是從專案的資料庫,開一個Default Template
,裡面的那個資料頁面模板直接關聯所有的國定假日。
為了方便編輯公式,我們先在這個資料庫中,多開公式欄位,這個欄位要顯示國定假日放假的日期區間中,所有的日期。舉個例子,如清明節假期是2024-04-04
到2024-04-07
,那麼要顯示@April 4, 2024,@April 5, 2024,@April 6, 2024,@April 7, 2024
。
這部分比較困難的部分,在於 Notion Formula 中沒有迴圈的函數,所以我們利用repeat()
達到類似的效果,迴圈效果請參考〈Notion Formula 2.0 § 基礎篇_2〉。
特別強調,這部分請在專案任務的資料庫中,針對專案日期區間也做一樣的效果。我們後面在進行比對運算時,需要讓他們都呈現 list 的資料結構。
lets(
d, prop("日期時間"),
天數, dateBetween(d.dateEnd(), d.dateStart(), "days"),
forLoop, "x".repeat(天數).split("x"),
if(
天數 == 0, d.dateStart(),
forLoop.map(d.dateStart().dateAdd(index, "days"))
)
)
首先,我們需要先映射國定假日的放假日期到專案任務資料庫中。
這裡要特別注意一點,我們需要使用flat()
函數,讓所有的列表變成一個列表。如果沒有使用flat()
,那它的架構其實是像這樣的(為了好閱讀,我把它們都變成英文字母代替):
[[A], [B, C, D, E, F, G, H], [I], [J, K, L, M]]
使用flat()
後,這一長串列表就可以變成單一個列表,也方便我們之後比較:
[A, B, C, D, E, F, G, H, I, J, K, L, M]
lets(
放假日期, map(prop("國定假日"),current.prop("放假日期")).flat(),
放假日期
)
當我們把放假日期與專案日期兩個欄位都變成 list 的資料形式後,就可以拿來比較啦~~使用filter()
與includes()
。
lets(
........
List_1, 放假日期,
List_2, 專案日期,
重疊日期, List_2.filter(List_1.includes(current)),
.........
)
當我們匹配出重複的日期後,可以利用sort()
、reverse()
和at()
判斷出這段日期區間裡的開始日期與結束日期。
PS. 這裡不要使用min()
、max()
,乍看下可以顯示開始日期與結束日期,但因為資料屬性的因素,後面會無法操作其他運算喲~
lets(
........
List_1, 放假日期,
List_2, 專案日期,
重疊日期, List_2.filter(List_1.includes(current)),
重疊_開始日期, 重疊日期.sort().at(0),
重疊_結束日期, 重疊日期.sort().reverse().at(0),
........
)
再將前面那段計算一般專案日期區間工作日的公式,拿來套用在重疊日期的區間,兩者相減就是扣掉國定假日的工作日計算方法啦~~~下面看完整公式。
lets(
/* 工作日計算 */
開始日期, prop("日期時間").dateStart(),
結束日期, prop("日期時間").dateEnd(),
開始日期_周幾, prop("日期時間").dateStart().day(),
區間天數, dateBetween(結束日期, 開始日期, "days"),
總天數, 區間天數 + 1,
區間周數, dateBetween(結束日期, 開始日期, "weeks"),
周末天數, 區間周數 * 2,
剩餘周末天數, min(max(開始日期_周幾 + 區間天數 % 7 - 5, 0), 2),
基礎工作天數, 總天數 - (周末天數 + 剩餘周末天數),
/* 放假日期映射到專案資料庫 */
放假日期, map(prop("國定假日"),current.prop("放假日期")).flat(),
/* 專案日期 */
d, prop("日期時間"),
days, dateBetween(d.dateEnd(), d.dateStart(), "days"),
forLoop, "x".repeat(days).split("x"),
專案日期, if(
days == 0, d.dateStart(),
forLoop.map(d.dateStart().dateAdd(index, "days"))
),
/* 假期涵蓋工作日計算 */
List_1, 放假日期,
List_2, 專案日期,
重疊日期, List_2.filter(List_1.includes(current)),
重疊_開始日期, 重疊日期.sort().at(0),
重疊_結束日期, 重疊日期.sort().reverse().at(0),
重疊_開始日期_周幾, 重疊_開始日期.day(),
重疊_區間天數, dateBetween(重疊_結束日期, 重疊_開始日期, "days"),
重疊_總天數, if(empty(重疊日期), 0, 重疊_區間天數 + 1),
重疊_區間周數, dateBetween(重疊_結束日期, 重疊_開始日期, "weeks"),
重疊_周末天數, 重疊_區間周數 * 2,
重疊_剩餘周末天數, min(max(重疊_開始日期_周幾 + 重疊_區間天數 % 7 - 5, 0), 2),
重疊工作天數, 重疊_總天數 - (重疊_周末天數 + 重疊_剩餘周末天數),
"一般工作天: " + format(基礎工作天數) + "\n"
+ "重疊工作天: " + format(重疊工作天數) + "\n"
+ "真正工作天: " + format(基礎工作天數 - 重疊工作天數)
)
這個「進階版工作日計算」花了我不少時間才完成,如果不需要將國定假日資料庫納入考量,根據以往的製作邏輯,應該能很快編輯完成。但因為我對新函數的功能還不夠熟悉,尤其是每種函數運作後的資料型態不太了解,使得整個過程相對辛苦。不過,完成這個練習讓我感到非常感動,未來只需定期更新國定假日的日期就可以持續運作啦~💪
這個公式明顯可以再精簡,不知道你有沒有想到呢?😂
如果你有任何想法,都可以與大家交流呀~
如果你想鼓勵我~歡迎請我喝杯咖啡 👉 贊助連結 ☕