NetworkDay

linkn00

New Member
Joined
Aug 15, 2019
Messages
44
Office Version
  1. 365
Platform
  1. Windows
I am using the script below to calculate the work day between two days in the power query. But it errors out when there is a negative result. For example, the end date is 3/7 but the start date is 3/9 (End days before the start day).
is there a way to allow this to give me a negative value if we have a negative result? Thank you so much

let
CountBusinessDays = (StartDate as date, EndDate as date) =>
let
numDays = Duration.Days(EndDate - StartDate) + 1,
weekends = List.Select(List.Dates(StartDate, numDays, #duration(1,0,0,0)),
each Date.DayOfWeek(_, Day.Monday) >= 5),
businessDays = numDays - List.Count(weekends)
in
businessDays
in
CountBusinessDays
 

Excel Facts

When they said...
When they said you are going to "Excel at life", they meant you "will be doing Excel your whole life".
Hi,
Take a look at following solution :
 
Upvote 0
Solution
Power Query:
(StartDate as date, EndDate as date) =>
let
    m = if StartDate <= EndDate then 1 else -1,
    numDays = Number.Abs(Duration.Days(EndDate - StartDate) + m),
    weekends = List.Select(List.Dates(StartDate, numDays, m * #duration(1,0,0,0)),
        each Date.DayOfWeek(_, Day.Monday) > 4),
    businessDays = m * (numDays - List.Count(weekends))
in
    businessDays
 
Upvote 0
The post from Enterprise DNA has a great function, but the web site used (2023 Federal Holiday Calendar | National Holidays | Federal Holidays) isn't helpful. It took forever to connect to, doesn't have any way to request a specific year, and provides just 6 tables of holidays with no indication of what year the tables are for. Dates are only given by Month Name and Date!
There is, however, a very useful site that lists days that the market is closed - Market Holidays for United States for 2023. I found it last year and at the time I found some errors in it - specifically it wasn't handling MLK day properly, but it was corrected shortly after I emailed them. Same thing with Juneteenth! Adding a year to the end of the URL - Market Holidays for United States for 1980 - will provide the calendar for that year.
Anyway, I wrote a PQ Function to create a Calendar Table of those dates:
Power Query:
let
    MarketHolidays = ( YearToGet as any ) as table =>
let
    Source = Web.Page(Web.Contents( "https://www.mypivots.com/market-holidays/united-states/" & Text.From( YearToGet ) )),
    HolCal = Source{0}[Data],
    ChangedType = Table.TransformColumnTypes( HolCal,{{"Date", type date}, {"Holiday", type text}}),
    SortedRows = Table.Sort(ChangedType,{{"Date", Order.Ascending}})
in
    SortedRows
in
    MarketHolidays
The Row Sort is because after adding Juneteenth it's listed after MLK day instead of after Memorial Day!
What I love about that function is making a table of Market Holidays for multiple years is a breeze.
Power Query:
let
    Source = {2000..2025},
    ConvertedToTable = Table.FromList(Source, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    InvokedfxMarketHolidays = Table.AddColumn(ConvertedToTable, "fxMarketHolidays", each fxMarketHolidays([Column1])),
    ExpandedfxMarketHolidays = Table.ExpandTableColumn(InvokedfxMarketHolidays, "fxMarketHolidays", {"Date", "Holiday"}, {"Date", "Holiday"}),
    ChangedType = Table.TransformColumnTypes(ExpandedfxMarketHolidays,{{"Date", type date}, {"Holiday", type text}}),
    RemovedOtherColumns = Table.SelectColumns(ChangedType,{"Date", "Holiday"})
in
    RemovedOtherColumns
Which produces a calendar of Market Holidays from 2000 to 2025.
Hope someone finds it useful!
 
Upvote 0
Power Query:
(StartDate as date, EndDate as date) =>
let
    m = if StartDate <= EndDate then 1 else -1,
    numDays = Number.Abs(Duration.Days(EndDate - StartDate) + m),
    weekends = List.Select(List.Dates(StartDate, numDays, m * #duration(1,0,0,0)),
        each Date.DayOfWeek(_, Day.Monday) > 4),
    businessDays = m * (numDays - List.Count(weekends))
in
    businessDays
As usual, great tight code.
I've tried to figure out how to make it like the NETWORKDAYS.INTL function - allow either a number or a 7 character string of 1's and 0's or either to indicate work and non-work days, and to remove holidays in a list, but it is way beyond my M Code skills.
Care to take a stab at it?
 
Upvote 0
M function named NetWorkDays:

Power Query:
(StartDate as any, EndDate as any, optional WeekEnd as any, optional Holidays as nullable list) as number =>
let
    startdate = Date.From(StartDate),
    enddate = Date.From(EndDate),
    m = if startdate <= enddate then 1 else -1,
    numDays = Number.Abs(Duration.Days(enddate - startdate) + m),
    weekend =  if Value.Is(WeekEnd, Number.Type) 
                then 
                    let tbl = Table.FromRows({
                        {1,"Saturday, Sunday","0000011"},{2,"Sunday, Monday","1000001"},{3,"Monday, Tuesday","1100000"},
                        {4,"Tuesday, Wednesday","0110000"},{5,"Wednesday, Thursday","0011000"},{6,"Thursday, Friday","0001100"},
                        {7,"Friday, Saturday","0000110"},{11,"Sunday only","0000001"},{12,"Monday only","1000000"},{13,"Tuesday only","0100000"},
                        {14,"Wednesday only","0010000"},{15,"Thursday only","0001000"},{16,"Friday only","0000100"},{17,"Saturday only","0000010"}})
                    in   tbl{[Column1 = WeekEnd]}[Column3]
                else
                    if WeekEnd = null then "0000011" else WeekEnd,
    dates = List.Dates(startdate, numDays, m * #duration(1,0,0,0)),
    weekendDayCount = List.Sum(List.Transform(dates, each 
        let n = Date.DayOfWeek(_, Day.Monday) in if Text.Middle(weekend, n,1) = "1" then 1 else 0)),
    holidayCount = if Holidays = null then 0 else List.Sum(List.Transform(List.Distinct(Holidays), each let dt = Date.From(_) in 
        if m*Duration.Days(dt - startdate)>=0 and m*Duration.Days(enddate - dt) >=0 and Text.Middle(weekend, Date.DayOfWeek(dt, Day.Monday),1) = "0" then 1 else 0)),
    businessDays = m * (numDays - weekendDayCount - holidayCount)
in
    businessDays

Query:
Power Query:
let
    Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
    HolidayList = Excel.CurrentWorkbook(){[Name="Holidays"]}[Content][Holidays],
    tbl = Table.AddColumn(Source, "NetWorkDays", each NetWorkDays([Start],[End],[Weekend Type], HolidayList)),
    Result = Table.RemoveColumns(tbl,{"Start", "End", "Weekend Type"})
in
    Result

pq networkdays.xlsx
ABCDEFGHIJKLM
1=TODAY()+RANDBETWEEN(-100,100)=TODAY()+RANDBETWEEN(1,100)=TODAY()+RANDBETWEEN(-100,100)
2Table1HolidaysQuery Output
3StartEndWeekend TypeHolidaysDOWNETWORKDAYS.INTLNetWorkDaysTest Result
44/10/20236/8/202301010105/1/202303030TRUE
52/7/20235/29/202311000004/9/202367575TRUE
62/21/20235/16/2023114/6/202336666TRUE
74/15/20235/17/202310010014/15/202351616TRUE
81/27/20231/9/202310101011/12/20233-7-7TRUE
91/8/20233/2/2023512/31/202253434TRUE
103/23/20231/10/202300101101/12/20233-37-37TRUE
116/10/20234/20/202301000003/21/20231-41-41TRUE
1212/15/20221/8/2023132/14/202311818TRUE
133/21/20235/27/2023111101112/15/2022399TRUE
143/2/20234/8/202311011114/28/2023455TRUE
155/17/20234/25/2023000110012/11/20226-15-15TRUE
165/7/202312/29/2022712/30/20224-84-84TRUE
176/5/20236/18/202311100106/11/2023655TRUE
185/16/20233/16/2023122/28/20231-47-47TRUE
193/12/20234/24/202310001016/19/202302121TRUE
202/22/20233/25/202312/20/202302121TRUE
214/29/20234/22/202310010005/31/20232-5-5TRUE
2212/26/20223/30/202351/20/202346060TRUE
235/5/20233/8/20231712/16/20224-46-46TRUE
246/20/20233/27/202311111005/10/20232-21-21TRUE
252/28/202312/29/202211-46-46TRUE
265/9/202312/6/20222-99-99TRUE
27
Sheet2
Cell Formulas
RangeFormula
F4:F24F4=WEEKDAY([@Holidays],3)
H4:H26H4=NETWORKDAYS.INTL(A4,B4,C4,Holidays[Holidays])
L4:L26L4=H4=J4
 
Upvote 0

Forum statistics

Threads
1,224,823
Messages
6,181,178
Members
453,021
Latest member
Justyna P

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top