NETWORKDAYS including Saturdays

G

Guest

How can I include all Saturdays in a perpetual calendar,yet exclude my array
of limited holidays AND exclude all Sundays using the NETWORKDAYS function?
Essentially, I want Excel to calculate the number of workdays in any given
month in any given year(include Saturdays) then subtract the days already
worked to give me the workdays left for the month perpetually. For example,
Aug 2007 we have 27 workdays, but in Aug 2008 we only have 26 workdays.
I know there's a more direct means than this:

I23 =IF((K23-J23)<=0,N23,(K23-J23)) N23 =1 (this gives me workdays left,
but does not exclude Sundays/holidays; yet, it's somewhat perpetual)
or
K22 =NETWORKDAYS(L23,K23, array of holidays)+IF(G23="AUG",4) this includes
the 4 Saturdays for the 2007 calendar & returns the desired value 27 for 2007
only.

J23 =TODAY()
K23 =EOMONTH(J23,0)
L23
=IF(G23="JUL","07/01/07",IF(G23="AUG","08/01/07",IF(G23="SEP","09/01/07",IF(G23="OCT","10/01/07",IF(G23="NOV","11/01/07",IF(G23="DEC","12/01/07"))))))
this is limited because it's not perpetual
 
A

Arvi Laanemets

Hi

Here is an UDF EnchWorkdaysN, which is an equivalent of NETWORKDAYS, but
allows you determine weekends at your choice (there are also 3 additional
functions, which perform some operations on arrays in VBA and are called
from NetWorkdaysN)


Option Base 1

Function SelectionSort(TempArray As Variant)
Dim MaxVal As Variant
Dim MaxIndex As Integer
Dim i, j As Integer

' The function sorts all entries in 1-dimensional array,
' it's a function provided in Microsoft KB article 133135

' Step through the elements in the array starting with the
' last element in the array.
For i = UBound(TempArray) To 1 Step -1

' Set MaxVal to the element in the array and save the
' index of this element as MaxIndex.
MaxVal = TempArray(i)
MaxIndex = i

' Loop through the remaining elements to see if any is
' larger than MaxVal. If it is then set this element
' to be the new MaxVal.
For j = 1 To i
If TempArray(j) > MaxVal Then
MaxVal = TempArray(j)
MaxIndex = j
End If
Next j

' If the index of the largest element is not i, then
' exchange this element with element i.
If MaxIndex < i Then
TempArray(MaxIndex) = TempArray(i)
TempArray(i) = MaxVal
End If
Next i

End Function

Function SelectionUnique(TempArray As Variant, Optional AllowZeros As
Boolean = True)
Dim MaxVal, TempArray2() As Variant
Dim MaxIndex As Integer
Dim i, j As Integer

' The function is meant to work with ordered arrays
' and removes all double entries and Null values
' (Except when the is the only value, and it is Null).
' Optional argument determines, how 0 values are processed

' Initialize
j = 1
ReDim TempArray2(1 To j) As Variant
TempArray2(1) = Null

' Step through the elements in the array starting with the
' first element in the array.
For i = 1 To UBound(TempArray) Step 1

If IsNull(TempArray(i)) Or _
IsEmpty(TempArray(i)) Or _
(TempArray(i) = 0 And AllowZeros = False) Then
Else
' Redim TempArray2 and add an element
ReDim Preserve TempArray2(1 To j) As Variant
TempArray2(j) = TempArray(i)
j = j + 1

' Set CurrVal to the element in the array
currval = TempArray(i)

' Cycle through next elements until value changes
k = 0
If i < UBound(TempArray) Then
Do While TempArray(i + k + 1) = currval
k = k + 1
If i + k > UBound(TempArray) Then Exit Do
Loop
End If
i = Application.WorksheetFunction.Max(i, i + k - 1)
End If

Next i

' Write the passed array over
TempArray = TempArray2

End Function

Function SelectionToInteger(TempArray As Variant)
Dim i As Integer

' The function cuts off decimal part from all non-empty elements of
array

' Step through the elements in the array starting with the
' first element in the array.
For i = 1 To UBound(TempArray) Step 1

If IsNull(TempArray(i)) Then
Else
' Replace array element with it's integer value
TempArray(i) = Int(TempArray(i))
End If

Next i

End Function


Public Function EnchWorkdaysN(StartDate As Date, _
EndDate As Date, _
Optional Holidays As Variant = Nothing, _
Optional Weekends As Variant = Nothing, _
Optional WeekStart As Integer = 1)


Dim arrayH As Variant, arrayW As Variant
Dim di As Date, dn As Date, dx As Date

' The result doesn't depend on order of values of first 2 parameters.

' When parameter Holidays is omitted, or Null, or not a positive numeric
(date) value,
' or not an array or cell range with numeric values, then no holidays
' are left out from day's count.

' When parameter Weekends is omitted, or Null, or not a numeric value
=1 and <8,
' or not an array or cell range with at least one numeric value between
=1 and <8,
' then 1 and 7 (Saturday and Sunday) are set for Weekend default walues,
' and according weekdays are left out from day's count.
' No weekends are left out from day's count (7-workday week) only then,
' when fourth parameter is set to FALSE.

' The parameter WeekStart determines, how are determined weekends in 4th
parameter
' Allowed values for parameter WeekStart are integers 1 to 7.
' The number 1 indicates Sunday as 1st day of week,
' the number 2 indicates Monday as first day of week, etc.
' When the parameter WeekStart is not between 1 and 7, then WeekStart =
(Abs(WeekStart) Mod 7)+1


' Initialize ArrayH
If TypeName(Holidays) = "Variant()" Then
ReDim arrayH(1 To UBound(Holidays)) As Variant
For i = 1 To UBound(Holidays)
arrayH(i) = IIf(VarType(Holidays(i, 1)) > 0 And
VarType(Holidays(i, 1)) < 8, Holidays(i, 1), Null)
arrayH(i) = IIf(arrayH(i) < 0, Null, arrayH(i))
Next i
ElseIf (VarType(Holidays) >= 8192 And VarType(Holidays) <= 8199) Or _
VarType(Holidays) = 8204 Then
ReDim arrayH(1 To UBound(Holidays.Value)) As Variant
For i = 1 To UBound(Holidays.Value)
arrayH(i) = IIf(VarType(Holidays(i)) > 0 And
VarType(Holidays(i)) < 8, Holidays(i), Null)
arrayH(i) = IIf(arrayH(i) < 0, Null, arrayH(i))
Next i
ElseIf VarType(Holidays) < 8 Then
ReDim arrayH(1) As Variant
arrayH(1) = Holidays
arrayH(1) = IIf(arrayH(1) < 0, Null, arrayH(1))
Else
ReDim arrayH(1) As Variant
arrayH(1) = Null
End If
' Sort arrayH
SelectionSort arrayH
' Replace non-integer values with integers
SelectionToInteger arrayH
' Remove double entries and empty elements
SelectionUnique arrayH


' Initialize arrayW
If VarType(Weekends) <> 11 Then
If TypeName(Weekends) = "Nothing" Then
ReDim arrayW(1 To 2) As Variant
arrayW(1) = 1
arrayW(2) = 7
ElseIf TypeName(Weekends) = "Variant()" Then
ReDim arrayW(1 To UBound(Weekends)) As Variant
For i = 1 To UBound(Weekends)
If UBound(Weekends) = 1 Then
arrayW(i) = IIf(VarType(Weekends(i)) > 0 And
VarType(Weekends(i)) < 8, ((Abs(Weekends(i)) + 12 + WeekStart) Mod 7) + 1,
Null)
Else
arrayW(i) = IIf(VarType(Weekends(i, 1)) > 0 And
VarType(Weekends(i, 1)) < 8, ((Abs(Weekends(i, 1)) + 12 + WeekStart) Mod 7)
+ 1, Null)
End If
arrayW(i) = IIf(arrayW(i) < 1 Or arrayW(i) >= 8, Null,
arrayW(i))
Next i
ElseIf VarType(Weekends) >= 8192 And VarType(Weekends) <= 8199 Or _
VarType(Weekends) = 8204 Then
ReDim arrayW(1 To UBound(Weekends.Value)) As Variant
For i = 1 To UBound(Weekends.Value)
arrayW(i) = IIf(VarType(Weekends(i)) > 0 And
VarType(Weekends(i)) < 8, ((Abs(Weekends(i)) + 12 + WeekStart) Mod 7) + 1,
Null)
arrayW(i) = IIf(arrayW(i) < 1 Or arrayW(i) >= 8, Null,
arrayW(i))
Next i
ElseIf (Int(Weekends) >= 1 And Int(Weekends) < 8) Then
ReDim arrayW(1) As Variant
arrayW(1) = ((Abs(Weekends) + 12 + WeekStart) Mod 7) + 1
arrayW(1) = IIf(arrayW(1) < 1 Or arrayW(1) >= 8, Null,
arrayW(1))
Else
ReDim arrayW(1 To 2) As Variant
arrayW(1) = 1
arrayW(2) = 7
End If
' Sort arrayW
SelectionSort arrayW
' Replace non-integer values with integers
SelectionToInteger arrayW
' Remove double entries and empty elements
SelectionUnique arrayW, False
Else
' Set 1st element to 0 for 7-workday week
ReDim arrayW(1) As Variant
arrayW(1) = IIf(Weekends = False, 0, Null)
End If

' When empty array, insert default values
If arrayW(1) = Null Then
ReDim arrayW(1 To 2, 1) As Variant
arrayW(1) = 1
arrayW(2) = 7
End If

' Calculate the number of workdays in date interval determined by
StartDay and EndDay
EnchWorkdaysN = 0
di = Application.WorksheetFunction.Min(StartDate, EndDate)
dn = Application.WorksheetFunction.Max(StartDate, EndDate)
dx = di
Do While dx <= dn
x = False
i = 1
Do While x = False And i <= UBound(arrayH) And TypeName(arrayH(1))
<> "Null"
x = (dx = arrayH(i))
i = i + 1
Loop
i = 1
Do While x = False And i <= UBound(arrayW) And arrayW(1) <> 0
x = (Weekday(dx) = arrayW(i))
i = i + 1
Loop
If Not (x) Then EnchWorkdaysN = EnchWorkdaysN + 1
dx = dx + 1
Loop
End Function
 
T

T. Valko

Try this:

A2 = start date
B2 = end date
C2:C10 = list of holiday dates

=SUMPRODUCT(--(WEEKDAY(ROW(INDIRECT(A2&":"&B2)),2)<7),--(ISNA(MATCH(ROW(INDIRECT(A2&":"&B2)),C2:C10,0))))
 
G

Guest

Also, our holidays are fixed with the exception of Memorial Day & Labor Day.
How can I tell Excel that they are holidays since the dates fluctuate year to
year?
 
G

Guest

Now that I have the correct number of workdays for each month, I need to
subtract the workdays already worked from this number to give the number of
workdays left. Any suggestions? My first best guess would be to continue
the formula and subtract from it another Indirect Weekday calculation for the
days that have passed.
 
T

T. Valko

Hmmm...

Well, you can use formulas to calculate the dates that those holidays will
fall on. Based on U.S. Federal Holiday guidlines Memorial Day is the last
Monday in May and Labor Day is the first Monday in September.

This formula will calculate the date for Memorial Day of the *current year*
:

="6/1"-WEEKDAY("6/1"+5)

This formula will calculate the date for Labor Day of the *current year* :

="9/1"-DAY("9/1")+8-WEEKDAY("9/1"-DAY("9/1")+1-2)
 
T

T. Valko

This formula will calculate the date for Labor Day of the *current year* :
="9/1"-DAY("9/1")+8-WEEKDAY("9/1"-DAY("9/1")+1-2)

We can reduce that to:

="9/1"-WEEKDAY("9/1"+5)+7
 
G

Guest

Sorry. Maybe my initial question was wrong. In another cell, I would like
to calculate the number of workdays already worked in the current month
(include Sat, exclude Holidays, etc.) Then in a third cell, I can subtract
the values from one another. The net result would give me 2 for example the
two workdays (8/30 & 8/31) left for this month.

I'm using the value 27 provided by the first formula you gave me to
calculate the average sales needed each day to meet budget for the current
month. However, I'm basing my projections on the workdays left to see if
I'm on track to meeting that monthly budget item.
 
G

Guest

Can the simpler function; COUNTIF, be used to obtain a value for days already
worked and have the formula exclude Sundays and Holidays for the current
month?
 
G

Guest

Will this formula consistantly give me the number of days already worked?

L23=Beginning of the month
J23=TODAY()

=SUMPRODUCT(--(WEEKDAY(ROW(INDIRECT(L23&":"&J23)),2)<7),--(ISNA(MATCH(ROW(INDIRECT(L23&":"&J23)),X25:X30,0))))
 
G

Guest

How does this look? :blush:)

=SUMPRODUCT(--(WEEKDAY(ROW(INDIRECT(EOMONTH(TODAY(),-1)+1&":"&EOMONTH(TODAY(),0))),2)<7),--(ISNA(MATCH(ROW(INDIRECT(EOMONTH(TODAY(),-1)+1&":"&EOMONTH(TODAY(),0))),X25:X30,0))))

Returns the value 27 & thus the workdays for August 2007.

=SUMPRODUCT(--(WEEKDAY(ROW(INDIRECT(EOMONTH(TODAY(),-1)+1&":"&TODAY())),2)<7),--(ISNA(MATCH(ROW(INDIRECT(EOMONTH(TODAY(),-1)+1&":"&TODAY())),X25:X30,0))))

Returns the value for the number of days already passed/worked for this month.
Thanks for your help T./Biff !!!
 
G

Guest

For Memorial Day, why did you use the 6/1 date? I'm having trouble following
the logic. Oh, and how 'bout a formula for Thanksgiving Day the third
Thursday in November?
 
T

T. Valko

Well, I see you started another thread asking the same questions so I'm
going to bail out of this one.
 
G

Guest

Sorry 'bout that Biff. If I offended you, please accept my apolgies. It was
'dark-thirty' when I sent the new one, not realizing to what end it would
accomplish.
Sincerely,
JIM
 
T

T. Valko

If I offended you, please accept my apolgies.

Not offended at all.

It's just that since you have 2 threads about the same subject you'd be
getting basically the same answers at both threads. So it's best to just
start a single thread and keep everything together.
 
H

hasrijadi

Dear smart guy...

how to make C2:C10 not counting.
coz if copy from this formula C2:C10 wiil counting to C3:C11 and so on.
I want this formula static with C2:C10. (not counting)

Best Regards
============
Hasri

EggHeadCafe - .NET Developer Portal of Choice
http://www.eggheadcafe.com
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top