34 summers ago, HP first Communicated
HP software assists in app management

Command file tests dates for holidays

Community contributor Dave Powell has improved upon a command file created by Tracy Pierce to deliver a streamlined way to tell an HP 3000 about upcoming holidays. Datetest tells whether a day is a holiday. "I finally needed something like that," Powell says, "but I wanted the following main changes:

1:  Boolean function syntax, so I could say :if  holiday()  then instead of
:xeq datetest
:if WhichVariableName = DontRememberWhatValue then

and also because I just think user-functions are cool."

"2. Much easier to add or disable specific holidays according to site-specific policies or even other countries’ rules. (Then disable Veterans Day, Presidents Day and MLK Day, because my company doesn’t take them.)

"3. Make it easy to add special one-off holidays like the day before/after Christmas at the last minute when the company announces them.

"Along the way, I also added midnight-protection and partial input date-checking, and made it more readable, at least to me."

Powell, who's contributed plenty of command files to the community through the HP 3000 newsgroup, says that most of the fun came in the day-of-week calculation.

I didn’t understand that part of Tracy’s script, or trust myself to adapt it without messing up, so I found a second method and used both, with a warning if the results didn’t agree. Surprise, surprise, they disagree about 12/25/2100, although they agree on dates I tested within the expected lifespan of MPE. So I shoveled in a third formula and found a day-of-week calculator spreadsheet, both of which agree with the second method. So anyone who uses Tracy’s original command file and plans to still run it in 2100 might need to make a change.

He offered what he called a preliminary version of the new datetest, which has been checked by Allegro's Steve Cooper.

option nolist
parm CCYYMMDD    =   ""
if   bound (HOL_ERRORS)    or    bound (HOL_DAY)
    deletevar   [email protected]
endif
setvar   HOL_ERRORS  0
if   "!CCYYMMDD"     =   ""
    setvar  HOL_CYMD    HPYYYYMMDD
    setvar  HOL_DAY     !HPDAY
    if  HOL_CYMD        <>  HPYYYYMMDD
#            if the date has changed, we just hit midnite and the
#            day-of-week we just set might be the new day; in this
#            case set the date & day-of-week again, and we should
#            be ok (unless the following 2 commands take 24 hours :)
        setvar  HOL_CYMD    HPYYYYMMDD
        setvar  HOL_DAY     !HPDAY
    endif
else
    setvar  HOL_CYMD    "!CCYYMMDD"
    if  not numeric (HOL_CYMD)
        echo **date parm, if entered, must be numeric**
        setvar  HOL_ERRORS  HOL_ERRORS + 1
    endif
    if  len (HOL_CYMD)   <>  8
        echo **date parm must be exactly 8 digits, unless omitted**
        setvar  HOL_ERRORS  HOL_ERRORS + 1
    elseif  numeric (HOL_CYMD)
        if  rht (HOL_CYMD, 2) > "31"
            echo **last 2 digits of date parm can't be more than 31**
            setvar  HOL_ERRORS  HOL_ERRORS + 1
        elseif  rht (HOL_CYMD, 2) = "00"
            echo **last 2 digits of date parm can't be "00"**
            setvar  HOL_ERRORS  HOL_ERRORS + 1
        endif
        if  str (HOL_CYMD, 5, 2) > "12"
            echo **bytes 5 & 6 of date parm can't be more than 12**
            setvar  HOL_ERRORS  HOL_ERRORS + 1
        elseif  str (HOL_CYMD, 5, 2) = "00"
            echo **characters 5 & 6 of date parm can't be "00"**
            setvar  HOL_ERRORS  HOL_ERRORS + 1
        endif
    endif
    if  HOL_ERRORS      >   0
        echo **exiting because the date-parm was not a valid**
        echo **8-digit date in yyyymmdd format **
        return FALSE
    endif
endif

#    -------------------------------------------------------
#    do not casually modify above here
#
#    Take any special / unofficial holidays here
#    OK to replace any dates that are past with the date of a
#    holiday the company just announced (Jewish new year,
#    days before / after Christmas & New Years, etc, etc)

if   HOL_CYMD="20080929"  or  HOL_CYMD="20081008" &
or   HOL_CYMD="20081226"  or  HOL_CYMD="20090102"
    echo It's a special company holiday :)
    return  TRUE
endif

#    do not casually modify below here
#    -------------------------------------------------------

setvar   HOL_YYYY    str (HOL_CYMD, 1, 4)
setvar   HOL_MM      str (HOL_CYMD, 5, 2)
setvar   HOL_DD      str (HOL_CYMD, 7, 2)

#
#    Set day of week, unless already set because processing "today"
#
if   not     bound (HOL_DAY)
#    1st, the method in the original "datetest" command file
    setvar  HOL_DAY str("000031059090120151181212243273304334", &
            !HOL_MM * 3 - 2, 3)
    setvar  HOL_DAY     !HOL_DAY + !HOL_DD
    IF  !HOL_MM > 2    and   ( !HOL_YYYY / 4 * 4 = !HOL_YYYY )
        setvar  HOL_DAY      HOL_DAY + 1
    ENDIF
    setvar  HOL_YWK     !HOL_YYYY - 1
    setvar  HOL_DAY     !HOL_DAY + ( !HOL_YWK / 400 ) * 146097
    setvar  HOL_YWK     !HOL_YWK  mod  400
    setvar  HOL_DAY     !HOL_DAY - ( !HOL_YWK / 100 ) * 36524
    setvar  HOL_YWK     !HOL_YWK mod 100
    setvar  HOL_DAY     !HOL_DAY + ( !HOL_YWK / 4 ) * 1461
    setvar  HOL_YWK     !HOL_YWK mod 4
    setvar  HOL_DAY     !HOL_DAY + ( !HOL_YWK * 365 )
    setvar  HOL_DAY     ( HOL_DAY mod 7 ) + 1
    deletevar HOL_YWK

#    Next, the method posted to the 3000-l by Mike Hornsby 06/04/2004
#    except, add 1 at the end because his was 0-6 and we need
#    1-7.
    setvar  HOL_XYR !HOL_YYYY-((12-!HOL_MM)/10)
    setvar  HOL_XMONTH !HOL_MM+(((12-!HOL_MM)/10)*12)
    setvar  HOL_XDAY !HOL_DD+(!HOL_XMONTH*2)+(((!HOL_XMONTH+1)*6)/10)
    setvar  HOL_XLEAP_YR (HOL_XYR/4) - (HOL_XYR/100) + (HOL_XYR/400)
    setvar  HOL_XDAY (HOL_XDAY+HOL_XYR+HOL_XLEAP_YR+1) mod 7  +  1

#    Next, day-of-week with my adaption of a "Zeller" formula
#    off the internet.
    if  HOL_MM      <   "03"
        setvar  HOL_ZMONTH  !HOL_MM  +  12
        setvar  HOL_ZYEAR   !HOL_YYYY   -   1
    else
        setvar  HOL_ZMONTH  !HOL_MM
        setvar  HOL_ZYEAR   !HOL_YYYY
    endif
    setvar  HOL_ZDAY    ( &
        ((13 * HOL_ZMONTH + 3) / 5)  +  !HOL_DD  +  HOL_ZYEAR &
    +   (HOL_ZYEAR/4) - (HOL_ZYEAR/100) + (HOL_ZYEAR/400) &
    +   1 )     mod 7   +   1

#    Now, see if the day-of-week calcs agree
    if  HOL_DAY     <>  HOL_XDAY &
    or  HOL_DAY     <>  HOL_ZDAY &
    or  HOL_ZDAY    <>  HOL_XDAY
        setvar  HOL_ERRORS  HOL_ERRORS + 1
        echo **day-of-week error**
        echo    HOL_DAY   =   !HOL_DAY
        echo    HOL_XDAY  =   !HOL_XDAY
        echo    HOL_ZDAY  =   !HOL_ZDAY
    endif
    setvar  HOL_DAY     HOL_ZDAY
    deletevar   [email protected][email protected]
ENDIF

#
#    Now check for specific regular holidays, month-by-month.
if   HOL_MM  =   "01"
    if  HOL_DD  =   "01"
        echo It's New Years Day
        return  TRUE
    endif
    if  ( !HOL_DAY=2  and  !HOL_DD>=15  and  !HOL_DD<=21 )
        echo (It's Martin Luther King day - but do we get it?)
#        return  TRUE
    endif
    return  FALSE
elseif   HOL_MM  =   "02"
    if  (!HOL_DAY=2  and  !HOL_DD>=15  and  !HOL_DD<=21)
        echo (It's President's Day - but do we get it?)
#        return  TRUE
    endif
    return  FALSE
elseif   HOL_MM  =   "05"
    if  (!HOL_DAY=2  and  !HOL_DD>=25  and  !HOL_DD<=31)
        echo It's Memorial Day
        return  TRUE
    endif
    return  FALSE
elseif   HOL_MM  =   "07"
    if  HOL_DD  =   "04"
        echo It's July 4th
        return  TRUE
    endif
    return  FALSE
elseif   HOL_MM  =   "09"
    if  ( !HOL_DAY=2  and  !HOL_DD>=1  and  !HOL_DD<=7 )
        echo It's Labor Day
        return  TRUE
    endif
    return  FALSE
elseif   HOL_MM  =   "11"
    if  HOL_DD  =   "11"
        echo (it's Veterans Day - but do we get it ?)
#        return  TRUE
    endif
    if  ( !HOL_DAY=5  and  !HOL_DD>=22  and  !HOL_DD<=28 )
        echo It's Thanksgiving
        return  TRUE
    endif
    if  ( !HOL_DAY=6  and  !HOL_DD>=23  and  !HOL_DD<=29 )
        echo It's the day after Thanksgiving
        return  TRUE
    endif
    return  FALSE
elseif   HOL_MM  =   "12"
    if  HOL_DD  =   "25"
        echo It's Christmas
        return  TRUE
    endif
    return  FALSE
endif

# showvar  [email protected]
return   FALSE
#    Function "holiday" to return 'TRUE' on company holidays
#    Dave Powell,    MMfab, Inc              05/12/2009
#
#    Syntax  if   holiday ()  then       <checks today>
#            calc holiday (20090511)
#            if   holiday ("20090511")   then
#            calc holiday (SomeDateVariable)
#            etc
#            or, for a company that sometimes has a few people in
#            Saturday morning, but its not like a real workday
#            setvar  OFFDAY    HOLIDAY()  or  HPDAY=1
#            setvar  WORKDAY   HPDAY<7  and  not OFFDAY
#            setvar  MAYBEDAY  not ( OFFDAY or WORKDAY )
#            etc
#
#    Logic adapted from the "datetest" command file
#    posted by Tracy Pierce on the HP-3000L on 09/26/2002
#
#    Variable-naming convention:
#    -   'DD', "MM",  "YYYY" etc mean string variables with the
#        length you might guess from the name.
#    -   'DAY', "YEAR", "MONTH" mean integer-type variables.
#
#    Changes / "improvements" in this file over original "datetest"
#    -   Function syntax, so you can say
#            if holiday() then
#        instead of
#            xeq datetest
#            if IForgetTheVariableName = WhatWasThatValue then
#    -   Separate "if"s for each holiday, to make it easier to
#        turn them on or off depending on your site's policies.
#    -   Then turns off some holidays I don't I think I can
#        count on MMfab always taking.
#    -   It echoes the name of whatever holiday it thinks it is,
#        do make debugging easier.
#    -   Has a spot to put in extra / unofficial days off when
#        the company announces them (like the day before / after
#        Christmas).
#    -   Returns true if the holiday falls on a Saturday or Sunday,
#        except Easter Sunday, which is ugly.
#    -   Midnite protection.
#    -   Checks that the date is numeric, with plausible month & day
#        (does not check that the day is too high for that month)
#    -   More readable ?
#    -   Calculates day-of-week three ways and compares them, as an
#        extra double-check since I don't understand any of
#        these calculations   :(
#    Downgrades:
#    -   Won't try to guess the century -- cannot handle 6-digit
#        input.
#
#
#    Any errors return "FALSE" on the assumption that the programmer,
#    at least, can't take a holiday until he fixes the bug  :)
#
#
#    Day-of-Week note:
#    The 3 methods mostly agree, but 12-25-2100 is a Sunday
#    according to method 1, but a Saturday according to methods
#    2 & 3.  Babwani's modified 2007 date-calc spreadsheet also
#    says Saturday.

Comments