i've been trying to explain to programmers for a very long time that there is a need for engineering in software which should follow the engineering of physical devices. lego blocks, spark plugs, light switches and so on, are engineered to be installed and forgotten. we do not have to know the chemical makeup of lego blocks, nor the electrical characteristics of the spark plug and light switch to use them.

i could construct a spark plug from a pair of wires with the end stripped off, but it would not be easy to use. it would be very primitive. i find a piece of code that loops through a range of dates to count monday-friday primitive. it is also slow. long ago i came up with my own formula and posted it on the universalthread where it was critiqued and improved.

now, i've refined that formula even more, and documented the operation of the formula thoroughly.

*
*  weekdays.prg
*  return the number of days that are monday - friday
*  in the passed date range without looping!
*
*  author:  mike yearwood with input from various
*                universalthread and foxite members.
*
*  usage:
*    ?weekdays({^2004-05-01},{^2004-05-31})
*
*  or:
*    ldfrom = {^2004-05-01}
*    ldto = {^2004-05-31}
*    lnweekdays = weekdays(m.ldfrom, m.ldto)
*    ?"the number of weekdays was: " + alltrim(str(m.lnweekdays)) + "."
*
*  returns:
*    a numeric value for the number of weekdays.
*    this also indicates the routine succeeded.
*    it crashes when called with incorrect parameters.
*
*  lparameters
*     tdfrom (r)     start of the date range.
*     tdto   (r)     end of the date range.
*
lparameters m.tufrom, m.tuto

local ;
  ldfrom, ldto, lndays, lndow

*martina jindrova suggested converting datetimes to dates.
*i use locals rather than the m.tufrom and m.tuto
*because if they were passed by reference, this function
*has no business altering the passed values.

*part 1 of the formula subtracts saturday and sunday from
*the end of the week(s).

**** m.lndays - (int(m.lndays / 7) * 2)

*the rest of the formula drops any leading
*saturday or sunday from any partial week.

*we could use iif() but that just makes
*the formula harder to read/write
*because (m.lndays % 7) is repeated as is
*sign(). both are calculated every time.
*sign() returns 1/0 instead of t/f.

*it seems the formula can be shortened
*without much impact on performance.

*there are three parts to consider.

*part1 determines if there is a
*partial week.
**** sign( (m.lndays % 7)

*part2 is looking to drop a leading
*saturday from that partial week.
**** + m.lndow - 7

*part3 is looking to drop a leading
*sunday from that partial week.
**** sign(m.lndow % 7)

*here's the result table where there are no
*remaining days. part 1 is 0.
*day  part1    part2   part3         1+2  3   1+2+3
*mon -(sign(0 + -6) + sign(1%7)) = -(-1 + 1) =  0
*tue -(sign(0 + -5) + sign(2%7)) = -(-1 + 1) =  0
*sat -(sign(0 + -1) + sign(6%7)) = -(-1 + 1) =  0
*sun -(sign(0 +  0) + sign(7%7)) = -( 0 + 0) =  0

*if there are remaining days, part 1 is 1.
*part2 and part3 trigger on saturday or sunday.
*day  part1    part2   part3         1+2  3   1+2+3
*mon -(sign(1 + -6) + sign(1%7)) = -(-1 + 1) =  0
*tue -(sign(1 + -5) + sign(2%7)) = -(-1 + 1) =  0
*sat -(sign(1 + -1) + sign(6%7)) = -( 0 + 1) = -1 && drop sat
*sun -(sign(1 +  0) + sign(7%7)) = -( 1 + 0) = -1 && drop sun

*original deprecated formula.
*!*   
lnreturn = m.lndays - (int(m.lndays / 7) * 2) ;
*!*        - iif(
m.lndow = 7, ;
*!*             sign(m.lndays % 7), ;
*!*       
     sign(m.lndow - 7 + (m.lndays % 7)) + 1)

ldfrom =
iif(vartype(m.tufrom)="t",ttod(m.tufrom),m.tufrom)
ldto =
iif(vartype(m.tuto)="t",ttod(m.tuto),m.tuto)

*determine the total
possible number of days.
lndays = (m.ldto - m.ldfrom) + 1

lndow
= dow(m.ldfrom,2)

return m.lndays - (int(m.lndays / 7) * 2) ;
    - (sign( (m.lndays % 7) + m.lndow - 7) + sign(m.lndow % 7))

Leave a Reply

Your email address will not be published. Required fields are marked *