Notes › Life Essays › A day on both the weekend list and the make-up list: which rule the workday tool obeys

A day on both the weekend list and the make-up list: which rule the workday tool obeys

Begin with the day that shows up on both lists

This kind of day turns up while a schedule is planned: the renovation crew says next Monday is a normal start, the calendar stamps that very Monday as a holiday, and a second sheet of paper says it is a make-up workday. My way is to drop the start and end dates into the tool and watch which list it obeys. This piece does not trace where a holiday list comes from; it only takes the internal order of checks apart, because swap the calendar or the region and that order stays the same.

The order of checks is four lines of code, not a policy

The function that decides what a single day is, wdKindOf(), sits at lines 512-517 of the template, and the sequence is not open to argument: it reads the make-up list first (line 514) and returns makeup, then the holiday list (line 515) and returns holiday, and only then the weekend switch (line 516). Only work and makeup are treated as working time.

Copy 2026-10-05, a Monday, into both lists and the measured kind comes back as makeup, while a one-day range prints workdays 1 / rest days 0 / total 1. The whole month says it more plainly: a block of dates written only on the holiday list gives 20 workdays, and copying part of it onto the make-up list turns that into 22, while the total never leaves 31. The only thing that shifts is the line between working and resting. The counting area also lays the collision open: 有效 3 条,其中 2 天同时写在补班清单里,按补班算, a tally of usable entries with the days on both lists resolved as make-up.

Weekend from 0 days up to 7, and the workday count collapses

You can set the weekend to any combination from 0 to 7 days. Hold the range at 2026-10 and leave both lists alone, and the workday count walks down a very tidy slope, while the two columns always add up to 31:

Days set as restWorkdaysRest daysTotal
0 days24731
1 day22931
2 days (default)191231
3 days151631
4 days112031
5 days82331
6 days52631
7 days22931

What happens at the bottom? Set all 7 days to rest and then per = 7 - 7 = 0, so the weekly batch and the remainder pass both fall to zero (lines 553-558): base=0, cut=0, only add still equals 2, and the month keeps nothing but 2 make-up days as working time. Clear both lists as well and the same month degenerates into workdays 0 / rest days 31 / total 31.

24 22 19 15 11 8 5 2 0 1 2 3 4 5 6 7 Workdays Rest days Total 31 2026-10

Fig. 1: the horizontal axis is how many days you declared as weekend, the green bars are the workdays left over, and the shortest bar is not 0 because make-up days still count as working.

No double subtraction and nothing missed: the year is plain addition

Pull the same rules up to a full year: 2026 holds 365 days, the weekend rule alone produces base=261, then 17 days are taken away and 4 are added back, which leaves 248 workdays / 117 rest days. The list plainly carries 29 holidays, so why take away only 17? Because 12 of them already land on a weekend, and a holiday sitting on a weekend is not taken away a second time; in return, all 4 make-up days land on a weekend, so add=4. The month view balances the same books: tick the checkbox on line 230 and the 12 monthly workday figures still sum to 248, identical to feeding the whole year in one pass.

Do the endpoints count? Four combinations differ by two days

Most quarrels over how many workdays are left are not arithmetic mistakes but endpoints that were never lined up. The two checkboxes at lines 170-171 of the template ship checked, so both ends are inside by default. Over 2026-10-14 through 2026-10-21 the four combinations measure 6 / 5 / 4 workdays, and excluding both ends shrinks the range to 10-15~10-20. Written as one and the same day, the four combinations come out as 1 / 0 / 0 / 0, and dropping both ends declares the range empty and prints 区间里一天都没有.

Which day sits N workdays away

Asking in the other direction is more common: a contract allows 500 workdays, on which date does delivery land. Counting 500 workdays forward from 2026-10-01 lands on 2028-09-04, spanning 704 calendar days, of which 204 are rest. Counting backwards travels too: from 2026-10-14 a step of -1 gives 2026-10-13, and N=0 hands back the start date where it stands even if that day is a Saturday. To reproduce any of it, use the projection mode of the workday calculator and do not anchor on today's system date. The ceiling is 1000000, and one extra digit is turned away outright; land exactly on that edge and what you meet is the boundary of the supported window, reported as 结果超出支持范围(1900-01-01 ~ 2999-12-31),还差 746094 个工作日, naming the remaining gap in workdays.

The range has no length limit, the detail list gives 200 rows

Those two facts belong apart. From 1900-01-01 to 2999-12-31 there are 401767 calendar days; pour them in at once and the tool still returns 286,964 workdays, integer arithmetic the whole way through. The detail list runs behind a different gate: 200 rows per kind, and a scan that stops after 4000 days. Feed it the 7305-day range 2000-01-01~2019-12-31 and the page writes out, word for word, 这段区间太长,只扫描了 4000 天,后面 3305 天没进列表, which says the range is too long, only 4000 days got scanned, and the trailing 3305 days never reached the list. Do not assume day-by-day decisions either: the range total is a weekly batch of weeks * (7 - weekendSize) plus a remainder handled one day at a time, and out of 401767 days only 2 ever enter the per-day branch. That is the same family of counting questions as why every 28 days drifts away from the same day each month.

List parsing: it reports bad lines but keeps the table

The list is a textarea, and what people paste into it is rarely clean. The parsing rule is to complain about broken lines without aborting the batch: a 10-line mixed list (9 lines with content, line 9 blank) measures as 有效 3 条(重复已去重 2 条), and the error panel quotes each offending line: line 5 has month 13, line 7 has 2026-02-30, a date that does not exist, and line 8 was typed without care; a blank line consumes a slot exactly like a # comment. Repeated lines never let one day be taken away twice: 3 lines naming the same date still finish at cut=1. The built-in data is 29 statutory holidays plus 4 make-up workdays, 33 days once merged and de-duplicated, covering one year only, 2026; from 2027 onward neither list holds a single day, cut=0 and add=0, and that year measures 261 workdays / 104 rest days, running purely through the weekend branch. Those two lists are sample data shipped inside the template, so another region simply means another list, while the order of checks stays the same.

2026 work 2027 work 2026 rest 2027 rest 248 261 117 104 in list: cut 17 add 4 outside: 0 / 0

Fig. 2: one and the same base=261 underneath, and the only difference comes from cut and add, 17 away and 4 back while the list is in force, 0 and 0 once it is not.

Three places where the copy and the code disagree

First, when start and end are typed the wrong way round, the error text invites the reader to press a button below and recompute in the reversed order, yet wdSwap() exists once in the whole template, defined at line 1223, with 0 onclick handlers, so that button was never rendered. Second, the origin of day numbering: the intro claims dates are converted into days counted from 1900-01-01, while the measurement returns wdDaysFromCivil(1970,1,1)=0 and (1900,1,1)=-25567, so 1900-01-01 is only the lower edge of the supported window. Third, and this one is what bites tomorrow: the weekend field is stored as a 33-character string, "falsefalsefalsefalsefalsetruetrue", whereas the reload condition demands a length of exactly 7 (line 1284), so both lists come back after a reload and the weekend ticks are gone.

FAQ

Q: a day sits on the holiday list and the make-up list together, is it subtracted once and added back once?

Neither. The make-up gate is examined before the holiday gate and the first hit returns at once: the month moves from 20 workdays to 22, and the total is still 31. When a single day is contested, priority is settled first, and counting how many days are left before a date behaves the same way.

Q: if all 7 weekend days are ticked, does the month stop working entirely?

It does not. per = 7 - 7 = 0 only zeroes the weekly batch and the remainder pass; the make-up list is still in place, so 2026-10 measures 2 workdays regardless, and you reach 0 / 31 / 31 only after clearing both lists together.

Q: can it recognize each coming year on its own?

It cannot. The two built-in lists are only sample data, and the year stops at 2026; every date outside them has to be pasted in, one line at a time.

📎 Related articles

How many characters fit on a copybook page: the default A4 gives 20, not 100 ÷ 4 = 25 2026-10-27 A Countdown Day Is 86400 Seconds, So DST Can Steal a Day 2026-10-27 Where the world clock offset comes from: one regex, and a hardcoded hour count that ignores daylight saving 2026-10-27 One calculation prints two body fat percentages: 6.1 points apart by default, 0.7 per 1 cm of waist 2026-10-26 A photo rotated 90° lies flat again on another device: how the EXIF flag and a real rotation split the work 2026-10-22