先看那一天同時出現在兩份清單裡
排工期最容易撞上這種日子:裝修工班說下週一照常進場,日曆上那個週一卻標著假期,另一張紙上又寫著補班。我的辦法是把起止日期丟進工具跑一遍,看它聽誰的——這篇不講假期清單哪來的,只講它內部的判定順序,因為換套日曆、換個地區,順序還是同一套。
判定順序是四行程式碼,不是政策
模板裡判單日性質的 wdKindOf() 寫在 512–517 行,順序硬得沒商量:先查補班清單(514 行)返回 makeup,再查假日清單(515 行)返回 holiday,最後才看週末開關(516 行);只有 work 與 makeup 算上班。
把 2026-10-05 這個週一同時抄進兩份清單,實測 kind 就是 makeup,單日區間給出 工作日 1 / 休息日 0 / 總數 1。整月對照更直白:同一批日期只寫進假日清單時是 20 個工作日,抄一份進補班清單變 22 個,總數始終 31——改掉的只有上班與休息這一刀。計數區還會把衝突攤開:有效 3 條,其中 2 天同時寫在補班清單裡,按補班算。
週末從 0 天設到 7 天,工作日一路塌下去
週末能設成 0 到 7 天任意組合。區間固定 2026-10、清單不動,工作日數走出一條很規整的下坡路,兩列相加永遠是 31:
| 設成休息的天數 | 工作日 | 休息日 | 總數 |
|---|---|---|---|
| 0 天 | 24 | 7 | 31 |
| 1 天 | 22 | 9 | 31 |
| 2 天(預設) | 19 | 12 | 31 |
| 3 天 | 15 | 16 | 31 |
| 4 天 | 11 | 20 | 31 |
| 5 天 | 8 | 23 | 31 |
| 6 天 | 5 | 26 | 31 |
| 7 天 | 2 | 29 | 31 |
塌到底會怎樣?設到 7 天全休息時 per = 7 - 7 = 0,整週批量與尾數判定一起歸零(553–558 行),base=0、cut=0,只有 add 仍=2,於是整月只剩 2 個補班日算上班。再把兩份清單清空,同一個月退化為 工作日 0 / 休息日 31 / 總數 31。
圖 1|橫軸是週末設幾天,綠柱是剩下的工作日;最矮那格不是 0,因為還有補班日算上班。
不重複扣、不漏加:全年只做加法
拉到整年:2026 全年 365 天,先按週末規則得到 base=261,再扣 17 天、加回 4 天,剩 248 個工作日 / 117 個休息日。清單裡明明有 29 條假日,怎麼只扣 17?因為有 12 條本來就落在週末頭上,週末的假日不再扣第二次;反過來 4 個補班日全都落在週末,所以 add=4。月度視圖也對得上帳:勾上 230 行那個核取方塊,12 個月的工作日逐月相加還是 248,與一次餵整年的結果相同。
端點算不算,四種組合差出兩天
「還剩幾個工作日」的爭吵多半不是算錯,而是首尾算沒算沒對齊。模板 170–171 行那兩個核取方塊預設都 checked,即首尾都含。2026-10-14 到 2026-10-21 四種組合實測 6 / 5 / 4 個工作日,都不含時區間縮成 10-15~10-20。寫成同一天時四種組合是 1 / 0 / 0 / 0,兩頭都不含直接判空並顯示「區間裡一天都沒有」。
數夠 N 個工作日那天是哪天
反過來問得更常:合約給了 500 個工作日,交付日落在哪天。實測 2026-10-01 往後數 500 個工作日落在 2028-09-04,跨 704 個自然日,其中 204 個是休息。往前數也走得動,2026-10-14 數 -1 就是 2026-10-13;N=0 原地返回起始日,哪怕那天是週六。想復現就用 工作日計算器 的推算模式,別拿系統當天當基準。上限 1000000,再多一位直接被拒;正好踩線時撞的是支援域邊界,報 結果超出支援範圍(1900-01-01 ~ 2999-12-31),還差 746094 個工作日。
區間沒有長度上限,明細只給 200 條
這兩件事得分開看。1900-01-01 到 2999-12-31 一共 401767 個自然日,一次餵進去照樣算出 286,964 個工作日,全程整數運算。明細清單卻是另一套閘門:每種只給 200 條、只掃描 4000 天,餵 2000-01-01~2019-12-31 這 7305 天的區間,頁面原樣寫出「這段區間太長,只掃描了 4000 天,後面 3305 天沒進清單」。也別預設它逐天判定:區間統計是整週批量 weeks * (7 - weekendSize) 加尾數逐個,401767 天裡進入逐日判定的只有 2 天。這跟 每 28 天與每月同一天為什麼會錯開是同一類口徑問題。
清單解析:報錯但不丟整表
清單是 textarea,貼進來的東西往往不乾淨。解析口徑是壞行報錯但不中斷:一份 10 行混合清單(9 行有內容、第 9 行是空行)實測給出 有效 3 條(重複已去重 2 條),錯誤面板逐行給原文——第 5 行是月份寫成 13、第 7 行是 2026-02-30 這個日子不存在、第 8 行是亂寫的一行;空行和 # 註釋一樣佔號。重複行絕不會讓某天被扣兩次:3 行寫同一個日子仍是 cut=1。清單規模是法定假日 29 條 + 調休補班 4 條、合併去重 33 天,年份只有 2026 一個;2027 起兩份清單裡一天都沒有,cut=0、add=0,全年實測 261 個工作日 / 104 個休息日,純走週末分支。那兩份清單只是模板內建的樣本資料,換個地區就換一份,判定順序仍是同一套。
圖 2|同一套 base=261,差別只來自 cut 與 add:清單內扣 17 加回 4,清單外是 0 和 0。
三處文案與程式碼打架
一是起止寫反時,報錯原文讓用戶「點下面按鈕按反過來的順序算」,可 wdSwap() 全文只有 1223 行那一處定義、0 處 onclick,那個按鈕並不存在。二是日序原點:intro 說日期換算成從 1900-01-01 起的天數,實測 wdDaysFromCivil(1970,1,1)=0、(1900,1,1)=-25567,1900-01-01 只是支援域下界。三最影響明天繼續用:weekend 欄位存成 33 字元的 "falsefalsefalsefalsefalsetruetrue",回讀條件卻要求長度正好 7(1284 行),於是兩份清單能回來、週末勾選重新整理即丟。
FAQ
Q:同一天既寫進假日清單又寫進補班清單,會不會被扣一次再加一次?
不會兩個都算。補班那關排在假日前面,第一個命中就返回:整月從 20 個工作日變 22 個,總數還是 31。搶一天時先定優先級,數距離某個日子還剩幾天也一樣。
Q:週末勾滿 7 天,是不是整月一天都不上班?
不是。per = 7 - 7 = 0 只讓批量與尾數歸零,補班清單還在,2026-10 實測仍有 2 個工作日;把兩份清單一起清空才得到 0 / 31 / 31。
Q:能不能讓它自己認得接下來每一年的假期?
不能。內建那兩份只是範例資料,年份只到 2026;清單外的日子得自己一行一條貼進去。