01 / 14Ten Tasks, Forty Days, Twenty-Eight on Site

Gantt Charts
Excel
Project Planning

How to Make a Gantt Chart in Excel With Working Days

The Programme Promised Handover on Friday 10 April and the Site Cannot Finish Before Tuesday 28 April, Because Forty Days of Work Were Booked Into Twenty-Eight Days of Calendar

9 Oct 202615 min read

UsesWORKDAYWEEKDAYAND, OR, NOTCOUNTIF

Hartcliffe Interiors planned a shop refit as ten tasks and forty working days. The programme sheet promised handover on Friday 10 April. The same ten tasks, booked on days the site is open, finish on Tuesday 28 April.

Nothing in the file is a guess. Every duration came from the trade that quoted it, and every finish date is the start plus the duration, which is the arithmetic anybody would write.

=B2+C2-1 counts Saturdays, Sundays and bank holidays as working time. Between 2 March and 10 April there are forty calendar days, and twelve of them are days when nobody is on site.

Programme span, 2 Mar to 10 Apr      40 calendar days
Working days inside it               28
Days of work in the ten tasks        40

Forty days of work will not fit into twenty-eight days of site time. The eighteen calendar days between the two handover dates are not a delay: they were never in the plan.

MeasureOn the programmeOn working days
Tasks1010
Days of work4040
First day on siteMon 02 MarMon 02 Mar
HandoverFri 10 AprTue 28 Apr
Slip—12 working days

A Gantt chart drawn from those dates is not wrong about the bars. It is wrong about the calendar underneath them, and it draws the error at full width, in colour, where it looks like a plan.

01Ten Tasks, Forty Days, Twenty-Eight on Site

Ten Tasks, Two Different Handover Dates

A shop refit broken into ten tasks, March to April 2026. Tasks are in A2:G11. Column B is the start the programme gave each trade, C is the duration the trade quoted in working days, D is the finish the sheet calculated with =B2+C2-1, and E is the finish the same duration lands on when Saturdays, Sundays and the two Easter bank holidays are skipped. Column F is how many working days apart those two finishes are. The holiday list sits in J2:J3 — Good Friday 3 April and Easter Monday 6 April 2026. The programme runs from Monday 2 March to Friday 10 April, which is forty calendar days containing twenty-eight working ones, and the ten tasks add up to forty days of work.

ABCDEFG
1
Task
Start
Days
Planned finish
Working finish
Days adrift
What the programme did
2
Strip out
Mon 02 Mar
4
Thu 05 Mar
Thu 05 Mar
0
The only task the two calendars agree on. Four days from Monday lands on Thursday either way, because no weekend falls inside it — which is exactly why nobody checked the next nine rows
3
First fix electrics
Fri 06 Mar
5
Tue 10 Mar
Thu 12 Mar
2
Five days from Friday runs through Saturday and Sunday on the programme and finishes Tuesday. On site it finishes Thursday, and the two lost days are never recovered
4
Plasterboard and skim
Wed 11 Mar
6
Mon 16 Mar
Fri 20 Mar
4
Six days over a weekend, and the slip doubles. The programme has the plasterers off site on Monday 16 March; the trade itself is still there on Friday 20 March
5
Flooring
Tue 17 Mar
4
Fri 20 Mar
Thu 26 Mar
4
The only row where the two finishes fall in the same week, which made the programme look recoverable. It is not: the start date is already four days out
6
Joinery install
Sat 21 Mar
7
Fri 27 Mar
Wed 08 Apr
6
The programme books the joiners in on a Saturday. Seven days of work spanning Easter is the longest task on the sheet and the one that carries the slip into April
7
Second fix electrics
Sat 28 Mar
3
Mon 30 Mar
Mon 13 Apr
8
A second Saturday start, and the three-day duration is honest — it is the date in front of it that is not. The electricians are booked for a day the building is shut
8
Decorating
Tue 31 Mar
5
Sat 04 Apr
Mon 20 Apr
9
The first finish date to land on a weekend. Five days from Tuesday 31 March crosses Good Friday as well, which is two of the twelve days the site is closed
9
Signage and shopfront
Sun 05 Apr
2
Mon 06 Apr
Wed 22 Apr
11
Booked to start on Easter Sunday and finish on Easter Monday. Both bank holidays are in the holiday list and neither was in the arithmetic
10
Snagging
Tue 07 Apr
3
Thu 09 Apr
Mon 27 Apr
12
By this row the slip has stopped growing: everything after Easter is weekends only, and two days a week is what the rest of the programme costs
11
Handover clean
Fri 10 Apr
1
Fri 10 Apr
Tue 28 Apr
12
One day of work, and the date on the client's letter. Friday 10 April on the programme, Tuesday 28 April on a calendar that knows what a Saturday is

fxCells with formulas are highlighted in green

Hover over formula cells to see the formula and highlight referenced cells

Columns D and E are the same ten durations read two ways. D is what the sheet calculated by adding days to a date; E is where those days land when the weekend is not a working day.

The two agree on the first task and on nothing after it. By the tenth row they are twelve working days apart, and twelve is exactly the number of Saturdays, Sundays and bank holidays inside the original span.

Three tasks are booked to start on a day the site is locked — Saturday 21 March, Saturday 28 March and Easter Sunday. Two more are booked to finish on one.

Scenario: Put =WEEKDAY(B2,2)>5 beside the start column of your own programme and fill it down. Every TRUE is a trade booked in for a day nobody will be there to let them in.

Try it in the grid

02WORKDAY: The Finish That Skips the Weekend

WORKDAY takes a start date and a number of working days and returns the date you land on, stepping over Saturdays, Sundays and every date in a holiday list:

=WORKDAY(B2,C2-1,Holidays)

On the plasterboard row that is six working days from Wednesday 11 March, and it returns Friday 20 March where the sheet had Monday 16 March. Same six days of work, four days further down the calendar.

The function does not care how many weekends it crosses. Ask for six working days and you get six working days, whether they sit inside one week or straddle Easter.

WORKDAY and NETWORKDAYS have shipped in every version since Excel 2007 and both exist in Google Sheets. The .INTL variants arrived in 2010.

A site that works Saturdays wants =WORKDAY.INTL(B2,C2-1,11,Holidays), where 11 means Sunday is the only weekend day. The weekend argument also takes a seven-character string of 1s and 0s for anything stranger.

Scenario: Write =WORKDAY(B2,C2-1,$J$2:$J$3) in a spare column beside your own durations and compare it with the finish dates already there. Any row where the two differ is a date you have promised somebody.

Try it in the grid

03The Minus One in Every Duration

A four-day task that starts on Monday finishes on Thursday, not Friday. The first day is one of the four, so the finish is the start plus three.

That is what the C2-1 is doing, and it is the single most common error in a hand-built programme. =WORKDAY(B2,C2) quietly adds a day to every task on the sheet.

Ten tasks, ten extra days, and the error compounds because each task starts from the task before it.

DurationStarts=WORKDAY(B2,C2)=WORKDAY(B2,C2-1)
1 dayMon 02 MarTue 03 MarMon 02 Mar
4 daysMon 02 MarFri 06 MarThu 05 Mar
5 daysFri 06 MarFri 13 MarThu 12 Mar

A one-day task is the test. If your formula says a one-day task finishes tomorrow, the minus one is missing, and every date below it is a day late.

Scenario: Add a one-day task to the bottom of your own programme and check that its finish date equals its start date. Fix the formula there, then fill it up the column.

Try it in the grid

04Each Task Starts on the Next Working Day

The start of each task is the finish of the one before it, moved on by one working day:

B3:  =WORKDAY(D2,1,Holidays)

=D2+1 is what the programme had, and it is why the joiners were booked in for Saturday 21 March. WORKDAY with a 1 moves a Friday finish to Monday and leaves a Tuesday finish on Wednesday.

Two formulas now run the whole plan: this one down the start column, and the WORKDAY finish down column D. Change any duration and every date below it moves.

Nothing in a working programme should be a typed date except the first start and the holiday list. A typed date in the middle is a dependency that stops working the moment anything above it changes.

Scenario: Turn on Formulas ▸ Show Formulas on your own programme and look down the start column. Every cell holding a date rather than a formula is a link in the chain that will not move when a duration changes.

Try it in the grid

05The Holiday List Is Part of the Formula

The third argument is a range of dates, and leaving it out is the second half of this fault. Good Friday and Easter Monday are two of the twelve days this programme worked through.

Put the dates in a column of their own, name the range Holidays, and both functions read the same list:

J2:  3 Apr 2026    Good Friday
J3:  6 Apr 2026    Easter Monday

A name beats $J$2:$J$3 because the list grows. Next year's dates go on the end, the name follows, and no formula needs editing.

Type the dates with =DATE(2026,4,3) if your workbook crosses regions. A date built that way cannot be read as 4 March by a machine set to a different order, which is how text dates get into the list in the first place.

A holiday that is text rather than a date returns #VALUE! — for the whole column, not just that row. It is the one error this setup throws, and it means somebody typed a date Excel did not recognise.

Empty cells inside the holiday range are ignored, so a named range with room to grow is safe. Duplicates are ignored too, which matters when two regions share a list.

Holidays that fall on a weekend are already skipped and count once. A Christmas Day on a Saturday with a substitute day on the Monday needs the Monday in the list, not the Saturday.

Scenario: Name your own holiday range Holidays in the Name Box, then put =COUNT(Holidays) in a spare cell. It should equal the number of dates you can see in the list; anything lower is a text date hiding in it.

Try it in the grid

06NETWORKDAYS Reads the Duration Back Out

NETWORKDAYS is WORKDAY run backwards: give it two dates and it counts the working days between them, including both ends:

=NETWORKDAYS(B2,D2,Holidays)

On every row of a correct programme that returns the number already sitting in the Days column. It is the cheapest check on the sheet, and it catches the one thing formulas cannot see.

A row where the check disagrees with the duration is a date somebody typed over. On this programme it disagrees on nine rows out of ten.

The same function answers the question the client asks. =NETWORKDAYS(B2,E11,Holidays) is the whole job in working days, and =E11-B2+1 is the same job in days off the wall calendar: 40 and 58.

Scenario: Add a check column of =NETWORKDAYS(B2,D2,Holidays)-C2 to your own programme. Every row should read 0, and sorting that column puts the typed-over dates at the top.

Try it in the grid

07The Timeline Is Conditional Formatting

A Gantt chart does not need a chart. Put one column per day across the top, point a conditional formatting rule at the block underneath, and the bars draw themselves:

L1:  =B2                       the first day on site
M1:  =WORKDAY(L1,1,Holidays)   and fill right

Select the grid from L2 down to the last task, open Home ▸ Conditional Formatting ▸ New Rule ▸ Use a formula, and give it one test:

=AND(L$1>=$B2,L$1<=$D2)

The dollar signs are the entire trick. L$1 locks the row so every cell reads the date header above its own column; $B2 locks the column so every cell reads the dates on its own row.

One rule paints every bar. Change a duration and the bars move with the dates, because the rule is reading the same two cells the formulas wrote.

Scenario: Build the header row across fifteen columns with =WORKDAY(L1,1,Holidays), apply that one rule to the block beneath it, and widen those columns to about 3 characters. The bars appear as you widen them.

Try it in the grid

08Shading the Days Nobody Is on Site

A timeline built on working days still has to show the days it skipped, or the bars look like they have gaps for no reason. Two more rules do it:

=WEEKDAY(L$1,2)>5              the weekend
=COUNTIF(Holidays,L$1)>0       the bank holidays

WEEKDAY with a second argument of 2 numbers Monday as 1, so anything above 5 is a Saturday or a Sunday. COUNTIF against the named list catches Easter.

Rule order decides which colour wins. Excel applies the rules top down, and where two rules set the same fill the higher one takes it. Put the weekend and holiday rules above the bar rule and tick Stop If True on both.

A bar that runs over a shaded weekend is telling the truth: the task is still open, and nobody is working on it. A bar that paints over the shading is the original mistake drawn in green.

Scenario: Open Conditional Formatting ▸ Manage Rules, drag the weekend rule to the top of the list and tick Stop If True. The grid should now show a grey stripe every Saturday and Sunday, straight through the bars.

Try it in the grid

09Painting Progress Inside the Bar

Add a per-cent complete column in H and a second bar rule fills in how much of each task is done. The done part of a bar ends a number of working days into it:

=AND(L$1>=$B2,L$1<=WORKDAY($B2,ROUND($C2*$H2,0)-1,Holidays))

$C2*$H2 is the days of work finished, ROUND turns 2.8 days into 3 because a column is a whole day, and the minus one is the same first-day rule as section 3.

This rule goes above the plain bar rule, without Stop If True, so the finished part is painted dark and the rest of the bar keeps the lighter fill underneath.

A progress bar is a claim, not a calculation. Nothing in the sheet knows how much is done, so the per-cent column has to come from somebody who was on site.

Scenario: Put 100%, 60% and 0% into the per-cent column for three tasks and add the rule above. Check that the 60% task is dark for three of its first days and light for the rest.

Try it in the grid

10The Bar Chart Version and Its Four Settings

A real chart is better when the plan leaves the sheet — a slide, a printed programme, a client pack. It is a stacked bar chart with two series, and it needs four settings before it looks like anything:

  1. Series 1 is the start dates, set to No fill. It is there to push the bar across the chart, not to be seen.
  2. Series 2 is the durations, in working days, from =NETWORKDAYS(B2,D2,Holidays).
  3. Categories in reverse order, on the vertical axis, or task 1 sits at the bottom and the plan reads upwards.
  4. The horizontal axis minimum typed as a date. Left on Automatic it starts at zero, and every bar is drawn from 1 January 1900.
SymptomSetting
Bars start at the left edgeAxis minimum is 0, type the first start date
Plan reads bottom to topCategories in reverse order
A solid block before each barSeries 1 still has a fill
Axis shows 46100, not a dateAxis number format is General

The chart cannot skip weekends. It draws a continuous date axis, so a task that spans a weekend is drawn two days longer than it is worked — which is the one thing the conditional formatting version gets right.

Scenario: Select A1:B11, insert a stacked bar chart, then add the duration column as a second series. Set series 1 to No fill and the axis minimum to 2 March 2026, and the programme appears.

Try it in the grid

11Does It Still Hit the Deadline?

The only question anybody asked is whether the shop opens on the day the lease says it does. One cell answers it:

=NETWORKDAYS(Deadline,MAX(E2:E11),Holidays)-1

MAX over the finish column is the day the job ends, because the last row is not always the latest date once tasks run in parallel. NETWORKDAYS counts both ends, so the minus one turns "same day" into zero.

On this programme the deadline is Friday 10 April and the answer is 12: twelve working days late, found in a cell rather than on site.

One more cell says who is on site this morning: =COUNTIFS($B$2:$B$11,"<="&TODAY(),$D$2:$D$11,">="&TODAY()) counts the tasks whose start has passed and whose finish has not.

Negative is slack and positive is late. A plan that answers 0 is a plan with no room in it at all, which is worth knowing before the first trade arrives.

Scenario: Put your own contractual date in a cell named Deadline and write that formula beside it. Then shorten one duration by two days and watch the number move, which is what a programme is for.

Try it in the grid

12Seven Things That Bite

  1. =B2+C2-1 instead of WORKDAY. It is right for calendar days and wrong for everything a trade quotes, and it fails quietly because the dates it returns are real dates.
  2. The missing minus one. =WORKDAY(B2,C2) makes every task a day longer; a one-day task finishing tomorrow is the tell.
  3. No holiday list. Two bank holidays at Easter and three in May move a summer programme by a working week.
  4. A text date in the holiday range. The whole column returns #VALUE!, and the fix is in the list, not the formula.
  5. Typed dates in the middle of the chain. They look identical to calculated ones and they do not move when a duration changes.
  6. Weekend shading below the bar rule. The bar wins the fill and the timeline stops showing the days the site is shut.
  7. A chart axis left on Automatic. Bars drawn from January 1900 are not a formatting problem, they are the axis minimum sitting at zero.

13Mini Exercises

  1. On the sample sheet, write =NETWORKDAYS(B2,D2,$J$2:$J$3) beside the first task and fill it down. Expect 4 on row 2 and a number smaller than the Days column on nine rows.
  2. Rebuild column D as =WORKDAY(B2,C2-1,$J$2:$J$3) and column B from row 3 as =WORKDAY(D2,1,$J$2:$J$3). Expect the last finish to move from Friday 10 April to Tuesday 28 April.
  3. Count the days off: =E11-B2+1 for the calendar span and =NETWORKDAYS(B2,E11,$J$2:$J$3) for the working one. Expect 58 and 40.
  4. Build the timeline header across fifteen columns and apply =AND(L$1>=$B2,L$1<=$D2). Confirm the first bar covers four columns.
  5. Delete Good Friday from the holiday list and recalculate. Expect the handover to move back one working day, to Monday 27 April.

What to Take Away

A Gantt chart is a picture of two columns of dates, and the picture is only ever as honest as they are. Every argument about a programme is really an argument about whether + or WORKDAY was used four columns to the left.

So the fault here is not the chart, and it is not the durations either. Each trade quoted the work correctly, in the only unit a trade uses, and the sheet then spent those days on Saturdays.

One WORKDAY in the finish column and one named holiday list would have shown the real date in February, when it was still a conversation about scope rather than a letter about handover. Twelve working days, ten tasks, and not a single wrong number anywhere on the sheet.

Share this article:
Back to Blog
Daily challenge · Day 67

Look up a consultant's billing rate from a two-way rate grid with INDEX and MATCH

A new exercise every day, solved in a real grid.

Solve today’s challenge