跳到主要內容跳到頁尾

跨日請假時數怎麼算:扣午休、週末與假日的逐日公式

6 分鐘閱讀摘要與日期

把請假區間拆到每天,分別計算與09–12、13–18兩個班段重疊的時間,再排除週末與自訂假日。提供Google Sheets完整LET、MAP公式及18個案例,處理跨日、假日首尾、午休、反向與空白輸入。

發布

文章目錄

我想算一段請假時間,從週五下午請到週一早上,中間的午休和週末都不能算進去。只用結束減開始,會把整個週末也一起算了;這篇用 LET、MAP 把區間拆到每天,分別計算和上下午班段重疊的時間。

先把規則寫清楚:上午 09:00–12:00、下午 13:00–18:00,週六日休息,再排除一份自訂假日清單。這是本篇的計算條件,沒有涵蓋輪班、補班日或跨午夜班段,實際假別怎麼計算仍要依你使用的規則另外設計。

輸入開始、結束與假日清單

在 B1 寫「請假開始」、C1 寫「請假結束」,B2、C2 放帶有日期的時間:

儲存格內容
B22026/10/16 10:00
C22026/10/16 11:00
E1請假小時數

10 點到 11 點完整落在上午班段,手算是 1 小時。換成 11 點到 14 點,則是上午 11–12 點加下午 13–14 點,應該只算 2 小時。

J1 寫「自訂假日」,J2:J4 放下面的日期。這幾筆是範例用的日期,10/20 在本例中被指定為假日,不是在宣告真實國定假日:

儲存格日期這筆的用途
J22026/10/20另外排除的日期
J32026/10/20重複日期不應再扣一次
J42026/10/18已經是週日,也不應重複扣

B2、C2 要是真正的日期時間數值,J 欄則放日期,不要夾帶時間。看起來像日期卻算不動時,先看 日期與時間入門,確認儲存格沒有被當成文字。

E2 的完整公式

把這條貼到 E2,輸出是以「小時」為單位的一般數值,先用數值格式看結果:

Google 試算表公式
fx

逐日計算上下午重疊時數,排除週末與J2:J4的假日

=LET( startAt, B2, endAt, C2, IF( OR(startAt="", endAt=""), "請填開始與結束", IF( OR(NOT(ISNUMBER(startAt)), NOT(ISNUMBER(endAt))), "請輸入有效日期時間", IF( endAt<startAt, "結束早於開始", ROUND( SUM( MAP( SEQUENCE(INT(endAt)-INT(startAt)+1, 1, INT(startAt), 1), LAMBDA( dayAt, IF( AND(WEEKDAY(dayAt, 2)<=5, COUNTIF($J$2:$J$4, dayAt)=0), MAX( 0, MIN(endAt, dayAt+TIME(12, 0, 0)) - MAX(startAt, dayAt+TIME(9, 0, 0)) ) + MAX( 0, MIN(endAt, dayAt+TIME(18, 0, 0)) - MAX(startAt, dayAt+TIME(13, 0, 0)) ), 0 ) ) ) )*24, 8 ) ) ) ) )

開頭那組 B2、C2 會得到 1。它已經乘過 24 換成小時,請別再把 E2 設成時刻格式,否則畫面會變成另一種意思。

整條比較長,我通常先確認開始、結束與假日範圍,再看下面的拆解。後面的式子片段都來自這條完整公式,閱讀時不用另外貼成小公式。

每天分開算上午與下午

LET 先把 B2 命名成 startAt,C2 命名成 endAt,後面就不用一直重寫儲存格位置。dayAt 則是當次正在處理的那一天,由 MAP 逐日傳進來。

以上午班段來說,dayAt+TIME(9,0,0) 是當天 09:00,dayAt+TIME(12,0,0) 是當天 12:00。要留下重疊時間,做兩件事:

  • MIN(endAt,dayAt+TIME(12,0,0)):結束不能晚於上午下班,所以拿兩者較早的時間。
  • MAX(startAt,dayAt+TIME(9,0,0)):開始不能早於上午上班,所以拿兩者較晚的時間。

較早的結束減掉較晚的開始,就是重疊長度。最外面再包一層 MAX(0,...),沒有重疊時就歸零,避免得到負數。

下午用同樣的方式,把班段改成 13:00–18:00,再把兩段相加。午休 12:00–13:00 沒有放進任何一段,自然就不會被算到,也不用事後猜這次應該扣幾次午休。

舉例來說,11:00–14:00 的上午交集是 11:00–12:00,下午交集是 13:00–14:00,所以是 2 小時。整段落在午休的 12:00–13:00,兩邊交集都為零。

拆出每一天,排除週末與假日

INT(startAt) 把開始時間的小數部分去掉,只留下日期;結束日期也用 INT(endAt) 取得。SEQUENCE 依這兩個日期產生每天的日期序列,從開始日走到結束日,首尾都保留。

接著 MAP 搭配 LAMBDA,把每個日期交給剛剛的兩段交集計算。這樣第一天只會留下請假開始後的部分,最後一天只會留下請假結束前的部分,中間完整的工作日則算完整班段。

每一天還要先通過這兩個條件,AND 要求兩者都成立:

  • WEEKDAY(dayAt,2)<=5:第二個參數用 2,週一是 1、週日是 7,所以只留下週一到週五。
  • COUNTIF($J$2:$J$4,dayAt)=0:假日清單沒有這一天,才計算班段;找到一次或重複找到,都會讓這一天歸零。

週末或假日直接回傳零,其他日子才加上午與下午的交集。SUM 加完所有日期後乘 24,把「一天的幾分之幾」換成小時。

日期時間換算成小時後,浮點數會有微小的尾數,例如保留 10 位小數仍可能出現 0.9999999999。所以末尾用 ROUND(…, 8) 收斂成 8 位;這邊只是整理數值誤差,沒有加入「不足半小時算半小時」之類的進位規則。

跨日、午休與假日案例

以下案例都沿用同一條公式與 J2:J4 的範例假日清單,只換開始、結束;每個結果的單位是小時。

情境開始結束結果
同日一小時2026/10/16 10:002026/10/16 11:001
跨午休2026/10/16 11:002026/10/16 14:002
完全午休2026/10/16 12:002026/10/16 13:000
超出上下班時間2026/10/16 08:002026/10/16 19:008
下班後2026/10/16 18:002026/10/16 19:000
週五到週一2026/10/16 17:002026/10/19 10:002
首日是週末2026/10/17 10:002026/10/19 10:001
末日是週末2026/10/16 17:002026/10/18 10:001
全區間都是週末2026/10/17 10:002026/10/18 17:000
首日是自訂假日2026/10/20 09:002026/10/21 18:008
末日是自訂假日2026/10/19 17:002026/10/20 18:001
中間有自訂假日2026/10/19 09:002026/10/21 18:0016

週五 17:00 到週一 10:00,只留下週五 17–18 點與週一 09–10 點,所以是 2 小時。10/19 早上到 10/21 傍晚則是週一、週三各 8 小時,週二 10/20 被假日清單排除,得到 16。

邊界與輸入不完整

公式開頭先檢查空白、是否為數字,再檢查結束有沒有早於開始。這些提示要先處理好,才不會把反向日期送進 SEQUENCE,或讓文字日期繼續往下算。

情境開始結束E 欄結果
反向區間2026/10/16 11:002026/10/16 10:00結束早於開始
開始空白(空白)2026/10/16 11:00請填開始與結束
相同時刻2026/10/16 10:002026/10/16 10:000
開始是文字不是日期2026/10/16 11:00請輸入有效日期時間
完整上午2026/10/16 09:002026/10/16 12:003
完整下午2026/10/16 13:002026/10/16 18:005

數值檢查會擋下「不是日期」這種文字,但一般數字也可能被當成日期序號,所以資料輸入端仍要確認日期範圍合理。這條公式沒有替使用者判斷每個輸入是不是一筆合理的請假申請。

換成自己的資料

一筆申請占一列時,把開始放 B 欄、結束放 C 欄,E2 的公式可以往下複製。B2、C2 會跟著列號移動,假日範圍 $J$2:$J$4 則固定不動;新增假日超過 J4 時,記得同步擴大這個範圍。

班段不同時,要一起改公式中的上午開始、上午結束、下午開始與下午結束四個 TIME。這篇的公式是照 09–12、13–18 的班段寫的;排班若還有補班、跨午夜或每天不同的時段,建議先整理逐日班表,再依那份班表重新設計公式。

只想知道兩個日期之間有幾個工作天,可以看 日期計算實戰 的 NETWORKDAYS;要換算時間或處理打卡差值,則看 時間函式與打卡工時。我是喜特先生,Mr. Sheet,我們下個教學見!

分享:
#請假時數#日期時間#LET#MAP
喜特先生 Mr. Sheet

喜特先生 Mr. Sheet

數據分析師/商業分析師

八年工作經驗,跨不同業界解決數據需求。做過的案例都整理在作品集。

接下來可以

相關文章

查看所有文章

留言討論

共 0 則留言

訂閱電子報,新文章上線就通知你

免費,隨時可取消。

送出即表示同意服務條款與隱私權政策。