A Holiday Dates  Perl program  is also available.
              #!/usr/bin/nawk -f
              # SccsId[] = "@(#)holidays.awk 1.24 12/02/11 (AWK holiday calculation/reporting program)"
              #----------------------------------------------------------------------#
              #                            holidays.awk                              #
              # -------------------------------------------------------------------- #
              #                                                                      #
              #   Copyright (c) 2003-2007 by Bob Orlando.  All rights reserved.      #
              #                                                                      #
              #   Permission to use, copy, modify and distribute this software       #
              #   and its documentation for any purpose and without fee is hereby    #
              #   granted, provided that the above copyright notice appear in all    #
              #   copies, and that both the copyright notice and this permission     #
              #   notice appear in supporting documentation, and that the name of    #
              #   Bob Orlando not be used in advertising or publicity pertaining     #
              #   to distribution of the software without specific, written prior    #
              #   permission.  Bob Orlando makes no representations about the        #
              #   suitability of this software for any purpose.  It is provided      #
              #   "as is" without express or implied warranty.                       #
              #                                                                      #
              #   BOB ORLANDO DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS           #
              #   SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY      #
              #   AND FITNESS.  IN NO EVENT SHALL BOB ORLANDO BE LIABLE FOR ANY      #
              #   SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES          #
              #   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER    #
              #   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,     #
              #   ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF     #
              #   THIS SOFTWARE.                                                     #
              #                                                                      #
              # -------------------------------------------------------------------- #
              #   Program documentation and notes located at the bottom of script.   #
              #----------------------------------------------------------------------#
              BEGIN \
              {
                progname = "holidays.awk"

               "date +\%Y\%m\%d" | getline Ymd # Escapes (\) in "\%Y\%m" prevents %Y
                close("date +\%Y\%m\%d")       # from looking like percentYpercent
                yyyy   = substr(Ymd,1,4)       # (an SCCS keyword)
                mm     = substr(Ymd,5,2)
                today  = substr(Ymd,7,2)
                yyyymm = yyyy""mm

                opt_B = 0
                opt_b = 0
                opt_d = 0
                opt_l = 0
                opt_m = 0
                opt_s = 0
                opt_t = 0
                mutex = 0 # Mutually exclusive options (bdls)
                error = 0

                #--------------------------------------------------------------#
                # Make 0-based weekdays, and 1-based month and julian arrays.  #
                #--------------------------------------------------------------#
                weekdayn["Sun"] = 0; weekdays[0] = "Sun"
                weekdayn["Mon"] = 1; weekdays[1] = "Mon"
                weekdayn["Tue"] = 2; weekdays[2] = "Tue"
                weekdayn["Wed"] = 3; weekdays[3] = "Wed"
                weekdayn["Thu"] = 4; weekdays[4] = "Thu"
                weekdayn["Fri"] = 5; weekdays[5] = "Fri"
                weekdayn["Sat"] = 6; weekdays[6] = "Sat"

                split("January  February March "     \
                      "April    May      June "      \
                      "July     August   September " \
                      "October  November December",  month_names)

                split("0 31 59 90 120 151 181 212 243 273 304 334 365", julian_days)
                split("0 31 60 91 121 152 182 213 244 274 305 335 366", julian_leap)
                split("31 28 31 30 31 30 31 31 30 31 30 31"           , month_days )

                bizdays[0] = 0 # Initialize

                #--------------------------------------------------------------#
                # Validate and process options and optargs.                    #
                #--------------------------------------------------------------#
                if (ARGV[1] == "-H") show_documentation(progname)

                if (ARGV[1] == "-h") exit_usage()
                                       #-------------------------------------#
                for (n=1; n<ARGC; n++) # -y = yyyy year (mostly testing)     #
                {                      #-------------------------------------#
                  if (ARGV[n] == "-y")
                  {
                    yyyy = ARGV[n+1]
                    if (yyyy !~ /^[0-2][0-9][0-9][0-9]$/)
                      exit_usage("Bogus year ("yyyy") in -y optarg!")

                    yyyy    = sprintf("%04d",yyyy)
                    yyyymm  = yyyy""mm # Use default month
                    ARGV[n] = ARGV[n+1] = ""
                    break
                  }
                }                      #-------------------------------------#
                for (n=1; n<ARGC; n++) # -m = mm month (mostly testing)      #
                {                      #-------------------------------------#
                  if (ARGV[n] == "-m")
                  {
                    mm = ARGV[n+1]
                    if (mm !~ /^[01]?[0-9]$/)
                      exit_usage("Bogus month number ("mm") in -m optarg!")

                    if (mm < 1 || mm > 12)
                      exit_usage("Invalid month number ("mm") in -m optarg!")

                    mm = sprintf("%02d",mm)
                    yyyymm  = yyyy""mm
                    ARGV[n] = ARGV[n+1] = ""
                    break
                  }
                }                      #-------------------------------------#
                for (n=1; n<ARGC; n++) # -B = Business day today? (ret 0|1)  #
                {                      #-------------------------------------#
                  if (ARGV[n] == "-B")
                  {
                    opt_B = 1; mutex++; ARGV[n] = ""; break
                  }
                }                      #-------------------------------------#
                for (n=1; n<ARGC; n++) # -b = Business day (ret yyyymmdd)    #
                {                      #-------------------------------------#
                  if (ARGV[n] == "-b")
                  {
                    opt_b = ARGV[n+1]         # Make opt_b the business day
                    mutex++
                    if (opt_b !~ /^(-?[0-2]?[0-9]|last)$/)
                      exit_usage("Bogus business day ("opt_b") in -b optarg!")

                    sub(/^-0+$/,"last",opt_b) # In case we get "-0".
                    ARGV[n] = ARGV[n+1] = ""
                    break
                  }
                }                      #-------------------------------------#
                for (n=1; n<ARGC; n++) # -l = Date list only (ret multiline) #
                {                      #-------------------------------------#
                  if (ARGV[n] == "-l")
                  {
                    opt_l = 1; mutex++; ARGV[n] = ""; break
                  }
                }                      #-------------------------------------#
                for (n=1; n<ARGC; n++) # -s = Date list only (ret one line)  #
                {                      #-------------------------------------#
                  if (ARGV[n] == "-s")
                  {
                    opt_s = 1; mutex++; ARGV[n] = ""; break
                  }
                }                      #-------------------------------------#
                for (n=1; n<ARGC; n++) # -t = Compare with today's date      #
                {                      #-------------------------------------#
                  if (ARGV[n] == "-t")
                  {
                    opt_t = 1; ARGV[n] = ""; break
                  }
                }                      #-------------------------------------#
                for (n=1; n<ARGC; n++) # -d = nth weekday (ret yyyymmdd)     #
                {                      #-------------------------------------#
                  if (ARGV[n] == "-d")
                  {
                    mutex++

                    nth = weekday = optarg = ARGV[n+1]
                    a_cnt = split(optarg,WWOA,".") # WWOA = Nth, Weekday, On/After
                    nth         = WWOA[1]
                    weekday     = WWOA[2]
                    on_or_after = WWOA[3]

                    if (nth !~ /^(-?[0-2]?[0-9])|(last)$/)
                      exit_usage("Bogus nth day ("nth") in -d optarg ("opt_d")!")

                    sub(/^-0+$/,"last",nth) # And just in case we get "-0".

                    if (weekday !~ /^(Sun|Mon|Tue|Wed|Thu|Fri|Sat|[0-6])$/)
                      exit_usage("Bogus weekday ("weekday") in -d optarg ("opt_d")!")

                    if (weekday !~ /^[0-6]$/)
                      weekday = weekdayn[weekday]

                    if (a_cnt >= 3)
                    {
                      if (on_or_after !~ /^[0-1]?[0-9]?$/)
                        exit_usage("Bogus on_or_after ("on_or_after") in -d optarg ("opt_d")!")
                    }
                    else
                      on_or_after = 1

                    if (on_or_after >= (month_days[mm+0] - 7))
                      exit_usage("You're kidding, right?  " \
                        month_names[mm+0] " only has "month_days[mm+0]"!")

                    yyyymmdd = holiday_date(yyyy,mm,nth,weekday,on_or_after)

                    opt_d = 1
                    exit # Go to END section (skip reading any holiday file).
                  }
                }                      #-----------------------------------#
                for (n=1; n<ARGC; n++) # Any other option is invalid.      #
                {                      #-----------------------------------#
                  if (ARGV[n] ~ /^-/)
                    exit_usage("Invalid option, '"ARGV[n]"'.")
                }

                shift_ARGV() # Drops nulled (blank) ARGV variables

                #----------------------------------------------------------#
                # If the user failed to supply a holidays fileid, push the #
                # following as an argument (and hope the file exists).     #
                #----------------------------------------------------------#
                if (ARGC < 2)
                {
                  ARGV[1] = "/usr/local/bin/holidays" # Default to this.
                  ARGC    = 2
                }
              } # BEGIN {}

              #======================================================================#
              #                               M A I N                                #
              #======================================================================#
              {
                sub(/\043.*/ ,"")   # Trash everything after pound sign.
                sub(/^[\t ]+/,"")   # Remove leading and
                sub(/[\t ]+$/,"")   #   trailing whitespace
                if ($0 ~ /^$/) next # Skip essentially blank lines.

                #------------------------------------------------------------#
                # Need New Year holiday for next year for Dec. last bizday.  #
                #------------------------------------------------------------#
                if ($1 ~ /^0?1$/ && $2 ~ /^0?1$/)
                {
                  new_years_day = 1
                  next_yyyy     = yyyy + 1
                  next_yyyymmdd = sprintf("%4d%02d%02d",next_yyyy,$1,$2)
                }
                else
                {
                  new_years_day = 0
                }

                on_or_after = 1
                #------------------------------------------------------------#
                # Process month and day.                                     #
                #------------------------------------------------------------#
                if ($1 ~ /^[01]?[0-9]$/ && $2 ~ /^0?[1-5]\.0?[0-6]\.?0?[0-9]?$/)
                { #          m   m                   nth.weekday.on_or_after
                  split($2,WWOA,".") # WWOA = Occurrence, Weekday, On/After
                  nth         = WWOA[1]
                  weekday     = WWOA[2]
                  on_or_after = WWOA[3]

                  if (on_or_after == "") on_or_after = 1

                  if (on_or_after >= (month_days[$1+0] - 7))
                  {
                    exit_usage("You're kidding, right?  " \
                      month_names[$1+0] " only has "month_days[$1+0]"!")
                  }
                  yyyymmdd = holiday_date(yyyy,$1,nth,weekday,on_or_after)
                  $1 = $2 = "" # Null these args
                }
                else if ($1 ~ /^[01]?[0-9]$/ && $2 ~ /^last\.0?[0-6]$/)
                { #               m   m                last.weekday.on_or_after
                  nth = weekday = $2
                  sub(/\..*/ ,"",nth    )
                  sub(/^.*\./,"",weekday)
                  yyyymmdd = holiday_date(yyyy,$1,nth,weekday)
                  $1 = $2 = "" # Null these args
                }
                else if ($1 ~ /^[01]?[0-9]$/ && $2 ~ /^[0-3]?[0-9]$/)
                { #               m   m                   d   d
                  yyyymmdd = sprintf("%4d%02d%02d",yyyy,$1,$2)
                  $1 = $2 = "" # Null these args
                }

                #------------------------------------------------------------#
                # If we have an adjustment by itself (i.e. for the day after #
                # Thanksgiving Day, then calculate that date.                #
                #------------------------------------------------------------#
                if ($3 ~ /^[+\-][0-9]+$/)
                {
                  yyyymmdd = dateplus(yyyymmdd,$3)
                  #----------------------------#
                  # Do the same for New Year.  #
                  #----------------------------#
                  if (new_years_day == 1)
                    next_yyyymmdd = dateplus(next_yyyymmdd,$3)
                  $3 = "" # Null this arg
                }

                #------------------------------------------------------------#
                # If we have a pattern that looks like [0-6][+\-][0-9]+ then #
                # test yyyymmdd's weekday to see if it matches DoW target.   #
                # If it does, adjust yyyymmdd by the +|- "adj" value and     #
                # recalculate the date.                                      #
                #------------------------------------------------------------#
                if ($3 ~ /0?[0-6]?[+\-][0-9][0-9]?/)
                {     #     target +|- adj
                  day = adj = $3
                  sub(/[+\-].*/,""  ,day)
                  sub(/[+\-].*/,":&",adj) # Negative value returns future date.
                  sub(/^.*:/   ,""  ,adj) # Positive returns past date.
                  $3 = "" # Null this arg
                  if (day_of_week(yyyymmdd) == day)
                    yyyymmdd = dateplus(yyyymmdd,adj)
                  #----------------------------#
                  # Do the same for New Year.  #
                  #----------------------------#
                  if (new_years_day == 1)
                    if (day_of_week(next_yyyymmdd) == day)
                      next_yyyymmdd = dateplus(next_yyyymmdd,adj)
                }

                #------------------------------------------------------------#
                # Remove leading whitespace from $0 and store the pertinents #
                # into our hash array (we'll print it in the END section).   #
                #------------------------------------------------------------#
                sub(/^[\t ]+/,"" ,$0) # Leading whitespace
                gsub(/[\t ]+/,"_",$0) # Change intervening whitespace to underscores

                if (holiday_hash[yyyymmdd] ~ /^$/)
                    holiday_hash[yyyymmdd] = weekdays[day_of_week(yyyymmdd)]":"$0
                if (new_years_day == 1)
                  if (holiday_hash[next_yyyymmdd] ~ /^$/)
                      holiday_hash[next_yyyymmdd] = weekdays[day_of_week(next_yyyymmdd)]":"$0
              } # End of M A I N

              END \
              {
                if (error > 0) exit error

                if (mutex > 1)
                  print "Options B, b, d, l, and s are mutually exclusive! ",
                        "We\047ll give it our best shot." | "cat 1>&2"

                if (opt_d) # Weekday date: give it and adios.
                { #--------------------------------------------------#
                  # If testing for "today" and today is the desired  #
                  # weekday, then exit 1 (true), printing nothing.   #
                  #--------------------------------------------------#
                  if (opt_t)
                  {
                    if (yyyymmdd == Ymd) exit 1
                    else                 exit 0
                  }

                  print yyyymmdd
                  exit substr(yyyymmdd,7,2)
                }

                holidays = ""

                #------------------------------------------------------------#
                # Since we already have our holidays in a hash, this is an   #
                # excellent place to get the business day.                   #
                #------------------------------------------------------------#
                if (opt_B) # See if today a business day?
                {
                  if (Ymd in holiday_hash) exit 0 # False if found in holiday hash.
                  else                     exit 1 # Else True.
                }

                if (opt_b) # Specific business day
                {
                  yyyy = substr(yyyymm,1,4)
                  if (opt_m) mm = sprintf("%02d",opt_m)
                  else       mm = substr(yyyymm,5,2)

                  #---------------------------------------------#
                  # Zero in on just the holidays for this month #
                  #---------------------------------------------#
                  for (holiday in holiday_hash)
                    if (match(holiday,yyyy""mm))
                      holidays = holidays" "holiday # Combine into a scalar list.

                  if (opt_b ~ /last|^-[0-2]?[0-9]$/)
                    rev_bizday=1
                  else
                    rev_bizday=0

                  mm_days = month_days[mm+0]
                  for (i=j=1; i<=mm_days; i++)
                  {
                    dd  = sprintf("%02d",i)
                    dow = day_of_week(yyyy,mm,dd)
                    #-----------------------------------------------------------#
                    # If day of week ! Sat or Sun and it's not a holiday, then  #
                    # if the day (i) is the same as the day we want (opt_b),    #
                    # print out the yyyymmdd date and exit with the month day.  #
                    # Else increment the business day counter (j) and continue. #
                    #-----------------------------------------------------------#
                    if (! (dow ~ /[06]/ || match(holidays," "yyyy""mm""dd)))
                    {
                      if (rev_bizday)
                      {
                        if (i <= mm_days)
                        {
                          bizdays[j] = dd # Push the date into bizdays array.
                          bizdays[0] = j
                          j++
                        }
                        else
                        {
                          break
                        }
                      }
                      else if (j == opt_b)
                      { #------------------------------------------------------#
                        # If testing for "today" and today is the desired      #
                        # business day, then exit 1 (true), printing nothing.  #
                        #------------------------------------------------------#
                        if (opt_t > 0)
                        {
                          if (yyyy""mm""dd == Ymd) exit 1
                          else                     exit 0
                        }
                        else
                        {
                          print yyyy""mm""dd
                        }
                        exit i
                      }
                      else
                      {
                        bizdays[0] = j
                        j++
                      }
                    } # if (dow !~ /[06]/ && ! match(holidays," "yyyy""mm""dd))
                  } # for (i=j=1; i<month_days[mm+0]; i++)

                  #--------------------------------------------------------------#
                  # If we want business day counting backward from EOM, do this. #
                  #--------------------------------------------------------------#
                  if (rev_bizday)
                  {
                    if (opt_b == "last")
                    {
                      if (opt_t > 0)
                        if (yyyy""mm""bizdays[bizdays[0]] == Ymd) exit 1
                          else exit 0

                      print yyyy""mm""bizdays[bizdays[0]]
                      exit dd
                    }

                    opt_b = opt_b - opt_b - opt_b # Reverse/remove the sign
                    if (opt_b < bizdays[0])
                    {
                      if (opt_t > 0)
                        if (yyyy""mm""(bizdays[bizdays[0] - opt_b]) == Ymd) exit 1
                          else exit 0

                      print yyyy""mm""bizdays[bizdays[0] - opt_b]
                      exit            bizdays[bizdays[0] - opt_b]
                    }
                    else if (opt_b == bizdays[0])
                    {
                      if (opt_t > 0)
                        if (yyyy""mm""dd == Ymd) exit 1
                          else exit 0

                      print yyyy""mm""bizdays[1]
                      exit            bizdays[1]
                    }
                  } # if (rev_bizday)

                  exit_usage("You're kidding, right?  " \
                    month_names[mm+0] " only has "bizdays[0]" business days!")
                  exit 0
                } # if (opt_b) # Business day

                #--------------------------------------------------------------------#
                # Display holidays saved in holiday_hash[].                          #
                #--------------------------------------------------------------------#
                for (holiday in holiday_hash)
                {
                  if (match(holiday,"^"yyyy))
                  {
                    if (opt_s)
                    {
                      holidays = holidays" "holiday # Combine into a scalar.
                      sub(/^ +/,"",holidays)        # Trim leading blank
                    }
                    else if (opt_l)
                      print holiday
                    else
                      print holiday":"holiday_hash[holiday]
                  }
                }

                if (opt_s)
                  print holidays

                exit 0
              } # END {}
              
              #======================================================================#
              #                     U S E R    F U N C T I O N S                     #
              #                        (in alphabetical order)                       #
              #----------------------------------------------------------------------#
              function basedate(                                               \
                                 YYYY,MM,DD,                                   \
                                 yyyy,cc,ddddd,leapdays,cc_leapdays,accum_days \
                               )                                                     #
              # -------------------------------------------------------------------- #
              # Globals: julian_days[] and julian_leap[]                             #
              #   Calls: leap_year()                                                 #
              #----------------------------------------------------------------------#
              {
                #------------------------------------------------------#
                # First, decrement the year and get the number of days #
                # for all the years preceeding it (in the Common Era). #
                #------------------------------------------------------#
                yyyy = YYYY
                if ((yyyy - 1) > 0)
                {
                  yyyy--
                  cc          = int(yyyy / 100)
                  ddddd       = yyyy * 365
                  leapdays    = int(yyyy / 4)
                  cc_leapdays = (cc > 0) ? (int(cc / 4)) : 0
                  ddddd       = ddddd + leapdays - cc + cc_leapdays
                  yyyy++
                }
                ddddd += DD

                #-------------------------------------------------------#
                # Add the previous month YTD days to our ddddd.  If it  #
                # is a leap year, assign julian_leap[] to accum_days[]. #
                # Then add in YTD days for previous months of this year #
                #-------------------------------------------------------#
                if (leap_year(yyyy))
                  for (i=0; i<13; i++) accum_days[i] = julian_leap[i]
                else
                  for (i=0; i<13; i++) accum_days[i] = julian_days[i]
                ddddd += accum_days[MM += 0] # 'MM += 0' removes leading zero

                return (ddddd)
              } # function base_date
              
              #----------------------------------------------------------------------#
              function calculate_date(YYYY,MM,DD,ADJ,  adj,yyyymmdd)                 #
              # -------------------------------------------------------------------- #
              # Calls: leap_year(), ddddd_to_yyyymmdd(), and basedate()              #
              #----------------------------------------------------------------------#
              {
                adj = ADJ
                if (adj ~ /\\055/)
                {
                  sub(/\\055/,"",adj)
                  yyyymmdd = ddddd_to_yyyymmdd(basedate(YYYY,MM,DD) - adj)
                }
                else
                {
                  sub(/\\053/,"",adj)
                  yyyymmdd = ddddd_to_yyyymmdd(basedate(YYYY,MM,DD) + adj)
                }

                return yyyymmdd
              } # function calculate_date()
              
              #----------------------------------------------------------------------#
              function dateplus(YYYYMMDD,ADJ,  mm,dd,yyyy,mmddyy)                    #
              # -------------------------------------------------------------------- #
              # Globals: ARGV[], ARGC, julian_days[], julian_leap[]                  #
              # Calls:   validate_yyyymmdd(), calculate_date()                       #
              # Exits on error.                                                      #
              #----------------------------------------------------------------------#
              {
                fname = "dateplus"

                #------------------------------------------------------------#
                # If last arg looks like a valid date, parse, validate, and  #
                # use it, else, use the current yyyymmdd.                    #
                #------------------------------------------------------------#
                if (YYYYMMDD ~ /^[0-2][0-9][0-9][0-9][0-1][0-9][0-3][0-9]$/)
                {
                  mm   = substr(YYYYMMDD,5,2)
                  dd   = substr(YYYYMMDD,7,2)
                  yyyy = substr(YYYYMMDD,1,4)
                  validate_yyyymmdd(yyyy,mm,dd)
                }

                #------------------------------------------------------------#
                # Positive (or unsigned) integer for adj days next?          #
                #------------------------------------------------------------#
                if (ADJ !~ /^[\+\-]?[0-9]+$/)
                {
                  print fname()" adjustment value ("ADJ")",
                   "not [+|-]numeric!" | "cat 1>&2"
                  exit 1
                }

                #------------------------------------------------------------#
                # Everything looks good, calculate/return new yyyymmdd date. #
                #------------------------------------------------------------#
                return calculate_date(yyyy,mm,dd,ADJ)
              } # function dateplus
              
              #----------------------------------------------------------------------#
              function day_of_week(YYYY,MM,DD,  adj,yyyy,mm,dow)                     #
              #----------------------------------------------------------------------#
              {
                if (length(YYYY) == 8)      # User may call us with yyyymmdd
                {                           # instead of yyyy,mm,dd
                  DD   = substr(YYYY,7,2)
                  MM   = substr(YYYY,5,2)
                  YYYY = substr(YYYY,1,4)
                }

                adj  = int((14 - MM) / 12)
                yyyy = YYYY - adj
                mm   = MM + (12 * adj) - 2
                dow  = (DD + yyyy              \
                           + int(yyyy/4)       \
                           - int(yyyy/100)     \
                           + int(yyyy/400)     \
                           + int(31 * mm / 12) \
                        ) % 7
                return dow
              } # function day_of_week()
              
              #----------------------------------------------------------------------#
              function ddddd_to_yyyymmdd(                                     \
                                          DDDDD,                              \
                                          ddddd,yyyy,cc,cc_leapdays,leapdays, \
                                          mmdd,julian,i                       \
                                        )                                            #
              # -------------------------------------------------------------------- #
              # Globals: julian_days[] and julian_leap[]                             #
              #----------------------------------------------------------------------#
              {
                #----------------------------------------------------------#
                # Reduce DDDDD arg to values in yyyy and ddddd variables.  #
                #----------------------------------------------------------#
                for (i=1; ; i++)
                {
                  yyyy        = int(DDDDD / 365) - i
                  ddddd       = DDDDD - yyyy * 365
                  cc          = int(yyyy / 100)
                  leapdays    = int(yyyy / 4)
                  cc_leapdays = (cc > 0) ? (int(cc / 4)) : 0
                  leapdays    = leapdays - cc + cc_leapdays
                  ddddd      -= leapdays
                  yyyy++
                  if (ddddd > 0) break
                }

                if (leap_year(yyyy))
                  for (i in julian_leap)
                    julian[i] = julian_leap[i]
                else
                  for (i in julian_days)
                    julian[i] = julian_days[i]

                #----------------------------------------------------------#
                # Reduce ddddd to month and day (we already have the year) #
                #----------------------------------------------------------#
                for (i=13; i>0; i--)
                {
                  if (julian[i] < ddddd)
                  {
                    ddddd -= julian[i]
                    mmdd = sprintf("%02d%02d",i,ddddd)
                    break
                  }
                }

                return (yyyy""mmdd)
              } # function ddddd_to_yyyymmdd
              
              #----------------------------------------------------------------------#
              function exit_usage(ERRMSG,  opts) # Global vars: progname, error      #
              #----------------------------------------------------------------------#
              {
                error = 5
                if (ERRMSG != "") print "\n"ERRMSG
                opts="-- -B [-b nn] [-d nn.Www.OnOrA ] -lHhst [-y yyyy] [-m mm]"
                print "\nUsage: [gn]awk -f "prog" "opts" holidayfile"                ,
                      "\n     --             = Allows passing script opts and args." ,
                      "\n     -B             = Return true if today is a business"   ,
                      "\n                      day."                                 ,
                      "\n     -b nn          = Return nn business day yyyymmdd date" ,
                      "\n                      (nn may also be \047last\047 for the" ,
                      "\n                      last business day of the month, and"  ,
                      "\n                      -n (minus n) may also be used for the",
                      "\n                      nth business day from end of month."  ,
                      "\n     -d n.Www[.OoA] = Return nth weekday (Www = Sun-Sat,"   ,
                      "\n        n.w[.OoA]     and the alternate, \047.w\047 takes"  ,
                      "\n                      0-6).  Optionally, an on-or-after"    ,
                      "\n                      (.OoA) day of the month may also be"  ,
                      "\n                      provided."                            ,
                      "\n     -H             = Full documentation (functions only"   ,
                      "\n                      when the current working directory"   ,
                      "\n                      is also the program directory)."      ,
                      "\n     -h             = Summary help (Usage)."                ,
                      "\n     -l             = Return multiline yyyymmdd date list." ,
                      "\n     -s             = Return a line of yyyymmdd\047s."      ,
                      "\n     -t             = Test resultant date against today"    ,
                      "\n                      (works with -b and -d options)."      ,
                      "\n     -y yyyy        = Use \047yyyy\047 as the year."        ,
                      "\n     -m mm          = Use the mm that follows as the month" ,
                      "\n                      (for business day calculations)."     ,
                      "\n     holidayfile    = Calculation directives file (not used",
                      "\n                      with \047-d\047 option).\n"           ,
                      "\n                     "progname" terminated.\n"
                exit error
              } # function exit_usage
              
              #----------------------------------------------------------------------#
              function holiday_date(                                              \
                                     YYYY,MM,NTH,DOW,ON_OR_AFTER,                 \
                                     fname,usage,wk,day,dd,mm_days,status,nth,dow \
                                   )
              # -------------------------------------------------------------------- #
              # Globals: month_names[]                                               #
              #----------------------------------------------------------------------#
              {
                fname = "holiday_date"
                usage = "Usage: "fname"(yyyy,mm, occurrence|'last', day_of_week)\n"

                #----------------------------------------------------------------#
                # Validate incoming args (we can skip yyyy here).                #
                #----------------------------------------------------------------#
                if (! (MM ~ /^[0-1]?[0-9]$/ || MM < 1 || MM > 12))
                {
                  print fname"(): Invalid month '"MM"'!\n" | "cat 1>&2"
                  exit 2
                }

                if (! (NTH ~ /^0?[1-5]$/ || NTH ~ /^last$/))
                {
                  print fname"(): Invalid occurrence, '"NTH"'!\n" | "cat 1>&2"
                  exit 3
                }

                if (DOW !~ /^0?[0-6]$/)
                {
                  print fname"(): Invalid Day of week '"DOW"'!\n" | "cat 1>&2"
                  exit 4
                }

                mm     = MM  + 0 # Assign and lose any leading zero.
                n      = (NTH ~ /^[0-9]$/) ? NTH + 0 : 5
                day    = DOW + 0 # Weekday (0=Sunday, 1=Monday, etc.).
                dd     = ""
                status = ""
                nth    = ""

                #----------------------------------------------------------------#
                # Passed validation, return the day of the month.  If user wants #
                # the last N-day, then get the number of days for that month and #
                # calculate the day using it.                                    #
                #----------------------------------------------------------------#
                if (mm ~ /^(1|3|5|7|8|10|12)$/) mm_days = 31
                else if (mm ~ /^(4|6|9|11)$/)   mm_days = 30
                else                            mm_days = leap_year(YYYY) ? 29 : 28

                #----------------------------------------------------------------#
                # If EOM day of the week is Sunday (0), then use 7 so the modulo #
                # operation (% 7) will work as expected (it doesn't seem to like #
                # negatives--sooooooooo sensative :-))                           #
                #----------------------------------------------------------------#
                dow = day_of_week(YYYY,MM,mm_days)
                if (dow == 0) dow = 7

                #----------------------------------------------------------------#
                # In case last occurrence is wanted, we back up a week at a      #
                # time to see if we can find the day within the number of days   #
                # allowed in our month.                                          #
                #----------------------------------------------------------------#
                for (; n>0; n--) # n already initialized.
                {
                  dd = (day - day_of_week(YYYY,MM,ON_OR_AFTER)) % 7
                  if (dd < 0) dd += 7
                  dd = (7 * n) - 6 + (dd % 7) + (ON_OR_AFTER - 1)
                  if (dd <= mm_days) break
                }

                if (dd > mm_days)
                {
                  if      (n ~ /1$/) nth = n"st"
                  else if (n ~ /2$/) nth = n"nd"
                  else if (n ~ /3$/) nth = n"rd"
                  else               nth = n"th"

                  #--------------------------------------------------#
                  # Don't sweat this for business day calculations.  #
                  #--------------------------------------------------#
                  if (! opt_b)
                  {
                    print "The "nth" occurrence of day "day" ("dd") exceeds",
                          month_names[mm]"\'s "mm_days" days!\n"
                    return 99
                  }
                }
                return YYYY""MM""sprintf("%02d",dd)
              } # function holiday_date
              
              #----------------------------------------------------------------------#
              function leap_year(YYYY) # YYYY = year.  Returns true|false (1|0).     #
              #----------------------------------------------------------------------#
              {
                return (((YYYY%4 == 0 && YYYY%100 != 0) || (YYYY%400 == 0)) ? 1 : 0)
              } # function leap_year
              
              #----------------------------------------------------------------------#
              function shift_ARGV(i,j,k)                                             #
              #----------------------------------------------------------------------#
              {
                k = ARGC
                for (i=1; i<=ARGC; i++)
                {
                  if (ARGV[i] == "")     # If the argument is empty, see is we
                  {                      # can shift the next one down to it.
                    for (j=i+1; j<=k; j++)
                    {
                      if (ARGV[j] == "") # If the next one is empty, try the one
                        continue         # following that.
                      ARGV[i] = ARGV[j]  # Once we find an argument, move it down,
                      ARGV[j] = ""       # null where it was, decrement arg counter,
                      break              # can do this with the next argument.
                    }
                  }
                }

                for (i=1; i<k; i++)      # Adjust ARGC
                  if (ARGV[i] == "")     # If the argument is empty,
                    ARGC--               # decrement ARGC
                return ARGC
              } # function shift_ARGV
              
              #----------------------------------------------------------------------#
              function show_documentation(MOI,  n,line)                              #
              #----------------------------------------------------------------------#
              {
                n = 0
                while (getline <MOI > 0) # Searching ourselves for the doc'n section.
                {
                  #------------------------------------------#
                  # Until we find the documentation section, #
                  # keep looking at each line.               #
                  #------------------------------------------#
                  if (n == 0)
                  {
                    if ($0 ~ /^\043 +D O C U M E N T A T I O N/)
                    {
                      n = 1
                      print line
                      print $0
                    }
                    else
                    {
                      line = $0
                    }

                    continue
                  }
                  else print # Once we find it, print until EOF.
                } # while (getline <MOI > 0)

                if (n == 0) # Means we did not find documentation section.
                {
                  print "NO DOCUMENTATION section found for "MOI" in the",
                        "current directory (cwd).\nTry again after first",
                        "changing to the program directory." | "cat 1>&2"
                  exit 1 # Exit failure
                }
                exit 1 # Exit failure anyway because we don'y live for this.
              } # function show_documentation
              
              #----------------------------------------------------------------------#
              function validate_yyyymmdd(                    \
                                          YYYY,MM,DD,        \
                                          yyyy,mm,dd,mm_days \
                                        )                                            #
              # -------------------------------------------------------------------- #
              # Globals: month_names[]                                               #
              # Calls:   leap_year()                                                 #
              # Exits on error.                                                      #
              #----------------------------------------------------------------------#
              {
                yyyy = YYYY
                mm   = MM
                dd   = DD
                mm  += 0

                if (mm==1||mm==3||mm==5||mm==7||mm==8||mm==10||mm==12)
                  mm_days=31
                else if (mm==4||mm==6||mm==9||mm==11)
                  mm_days=30
                else if (mm==2)
                  mm_days = (leap_year(yyyy)) ? 29 : 28
                else
                {
                  printf("Month %02d is invalid.\n",mm) | "cat 1>&2"
                  exit 6
                }
                if (dd > mm_days)
                {
                  printf("%s, %d does not have %d days.\n",
                    month_names[mm],yyyy,dd) | "cat 1>&2"
                  exit 7
                }
                return 0
              } # function validate_yyyymmdd

              #======================================================================#
              #                       D O C U M E N T A T I O N                      #
              #======================================================================#
              #                                                                      #
              #      Author: Bob Orlando (Bob@OrlandoKuntao.com)                     #
              #                                                                      #
              #        Date: February 1, 2003                                        #
              #                                                                      #
              #  Program ID: holidays.awk                                            #
              #                                                                      #
              #       Usage: [gn]awk -f holidays.awk -- -B [-b nn] [-d n.Www.OoA] \  #
              #                      -lHhst [-y yyyy] [-m mm] holidayfile            #
              #                                                                      #
              #               nawk|gawk      = Program runs with either. (See "Usage #
              #                                Note:" below for "#!" operation.)     #
              #                 --           = Allows passing script opts and args.  #
              #                 -B           = Return true if today is a business    #
              #                                day.                                  #
              #                 -b nn        = Return nn business day as yyyymmdd    #
              #                                (nn may also be specified as "last"   #
              #                                for that business day of the month,   #
              #                                or -n (minus n) for nth business day  #
              #                                from end of the month).               #
              #                 -d n.Www.OoA = Return nth weekday (Www = Sun-Sat,    #
              #                                and "n" may also be given as "last"   #
              #                                for the last "Www" day of the month). #
              #                 -d n.w.OoA   = Alternate suntax for the above only   #
              #                                the ".w" is 0-6 for Sun-Sat.  The     #
              #                                ".OoA" is an optional on-or-after     #
              #                                day of the month that says the date   #
              #                                want must be on or after the OoA'th   #
              #                                day of the month.                     #
              #                 -H           = Full formal documentation (functions  #
              #                                only when the current working         #
              #                                directory is the program directory).  #
              #                 -h           = Summary help (Usage).                 #
              #                 -l           = Return multiline yyyymmdd date list.  #
              #                 -s           = Return a single line of yyyymmdd's.   #
              #                 -t           = Test resultant date against today     #
              #                                (works with -b and -d options).       #
              #                 -y yyyy      = Use yyyy for the year.                #
              #                 -m mm        = Use the mm that follows as the month  #
              #                                (for business day calculations).      #
              #               holidayfile    = Calculation directives file (neither  #
              #                                used nor needed with "-d" option).    #
              #                                The file lays out as follows:         #
              #                                                                      #
              #                                                                      #
              #     Example: awk -f /home/awk/holidays.awk -- -y 2013           \    #
              #                /home/awk/SocialSecurity.txt                     \    #
              #                | sed -n 's/^\(....\)\(..\)\(..\)\(.*\)/\2-\3/p' \    #
              #                | sort                                                #
              #                                                                      #
              #       Using SocialSecurity.txt for 'holidayfile' to return the       #
              #       4th Wednesday of every month ...                               #
              #                                                                      #
              #     > #------------------------------------------------------------# #
              #     > # Mm N.Day Adj Holiday name                # Comments        # #
              #     > # -- ----- --- --------------------------- ----------------- # #
              #     >   01 4.3       4th Wednesday               # 4th Wed in Jan    #
              #     >   02 4.3       4th Wednesday               # 4th Wed in Feb    #
              #     >   03 4.3       4th Wednesday               # 4th Wed in Mar    #
              #     >   04 4.3       4th Wednesday               # 4th Wed in Apr    #
              #     >   05 4.3       4th Wednesday               # 4th Wed in May    #
              #     >   06 4.3       4th Wednesday               # 4th Wed in Jun    #
              #     >   07 4.3       4th Wednesday               # 4th Wed in Jul    #
              #     >   08 4.3       4th Wednesday               # 4th Wed in Aug    #
              #     >   09 4.3       4th Wednesday               # 4th Wed in Sep    #
              #     >   10 4.3       4th Wednesday               # 4th Wed in Oct    #
              #     >   11 4.3       4th Wednesday               # 4th Wed in Nov    #
              #     >   12 4.3       4th Wednesday               # 4th Wed in Dec    #
              #                                                                      #
              #       the following output was generated:                            #
              #                                                                      #
              #         01-23                                                        #
              #         02-27                                                        #
              #         03-27                                                        #
              #         04-24                                                        #
              #         05-22                                                        #
              #         06-26                                                        #
              #         07-24                                                        #
              #         08-28                                                        #
              #         09-25                                                        #
              #         10-23                                                        #
              #         11-27                                                        #
              #         12-25                                                        #
              #                                                                      #
              #                                                                      #
              #   Data File: holidays                                                #
              #                                                                      #
              #     > #------------------------------------------------------------# #
              #     > #  *  DO NOT REMOVE  *  DO NOT REMOVE  *  DO NOT REMOVE  *   # #
              #     > #------------------------------------------------------------# #
              #     > # This file contains values that allow any program to        # #
              #     > # calculate holidays using either fixed month and day or by  # #
              #     > # specifying an occurrence in a month like the 4th Thursday  # #
              #     > # in November or "last" Monday in May. Adjustments also are  # #
              #     > # permitted for those fixed holiday dates that fall on       # #
              #     > # weekends but are observed either the Friday before or the  # #
              #     > # Monday after, as well as days like the Friday after the    # #
              #     > # Thanksgiving Day observance (U.S.).                        # #
              #     > #                                                            # #
              #     > # Leading whitespace is ignored, as is everything following  # #
              #     > # and including the octothorpe (#-sign).                     # #
              #     > #                                                            # #
              #     > # Mm N.D.OnOrA Adj Holiday name            # Comments        # #
              #     > # -- --------- --- ----------------------- ----------------- # #
              #     >   01  1            New Year's              # M-F               #
              #     >   01  1        6-1 New Year's (pre-obs)    # Sat? Use Fri      #
              #     > # 01  1        6+2 New Year's (post-obs)   # Sat? Or Monday    #
              #     >   01  1        0+1 New Year's (post-obs)   # Sun? Use Mon      #
              #     >   01  3.1          M.L.King Jr. Birthday   # 3rd Mon in Jan    #
              #     >   05  last.1       Memorial Day            # Last Mon in May   #
              #     >   07  4            Independence            # M-F               #
              #     >   07  4        6-1 Independence (pre-obs)  # Sat? Use Fri      #
              #     >   07  4        0+1 Independence (post-obs) # Sun? Use Mon      #
              #     >   09  1.1          Labor Day               # 1st Mon in Sep    #
              #     >   11  4.4          Thanksgiving (US)       # 4th Thu in Nov    #
              #     >   11  4.4       +1 Thanksgiving Day II     # Fri after         #
              #     >   12 25            Christmas               # M-F               #
              #     >   12 25        6-1 Christmas (pre-obs)     # Sat? Use Fri      #
              #     >   12 25        0+1 Christmas (post-obs)    # Sun? Use Mon      #
              #     > #------------------------------------------------------------# #
              #     > # Unique dates.                                              # #
              #     > #------------------------------------------------------------# #
              #     > # 04  1.0.6        Falklands ST Beg  # 1st Sun on/after Apr 6  #
              #     > # 09  1.0.8        Falklands DST Beg # 1st Sun on/after Sep 8  #
              #                                                                      #
              #                                                                      #
              #  Usage Note: If your OS recognizes the "#!" (shebang) syntax,        #
              #              you can place a "#!/usr/bin/nawk -f" (or gawk)          #
              #              at the start of this program (as I have) thereby        #
              #              allowing you skip the "[gn]awk -f" during invocation.   #
              #                                                                      #
              #                                                                      #
              #     Purpose: Return the year's holiday dates and names as calculated #
              #              from the values in a holidays file.  A good description #
              #              of what this program does is provided in the holiday    #
              #              file layout just below.  Optionally (-b), return the    #
              #              yyyymmdd date for the nth business day of the month.    #
              #                                                                      #
              #                                                                      #
              # Description: Although I have Perl modules that do the same thing, I  #
              #              wanted an awk program to provide the same information   #
              #              so I could use it in my shell scripts.                  #
              #                                                                      #
              #              The program outputs holidays in three forms:            #
              #                                                                      #
              #                 1. Dates (yyyymmdd) only with all dates on a         #
              #                    single line.                                      #
              #                 2. Dates only in a multiline list.                   #
              #                 3. yyyymmdd:Day:Holiday_name_as_in_holidays_file     #
              #                                                                      #
              #              The user can parse or assign the output as needed       #
              #              via any number of shell script or other language tools. #
              #                                                                      #
              #                                                                      #
              #       ------ Here is an example of one such shell script ------      #
              #                                                                      #
              #       > #!/bin/sh -vx                                                #
              #       >   bin=/usr/local/bin                                         #
              #       >   holidays_awk=$bin/holidays.awk                             #
              #       >   holiday_file=$bin/holidays                                 #
              #       >   holiday_cmd="nawk -f $holidays_awk --"                     #
              #       >                                                              #
              #       >   HOLIDAYS=`$holiday_cmd -s $holiday_file`; export HOLIDAYS  #
              #       >                                                              #
              #       >   if [ ."`echo $HOLIDAYS | grep \`date +\%Y\%m\%d\``" != . ] #
              #       >   then                                                       #
              #       >      echo "Today is a holiday.  Hoo-rah! :-)"                #
              #       >   fi                                                         #
              #       >                                                              #
              #       >   #------------------------------------------------------#   #
              #       >   # Display holidays for this year.                      #   #
              #       >   #------------------------------------------------------#   #
              #       >   $holiday_cmd $holiday_file | sort \ k -- $holiday_file`    #
              #       >     | nawk -v today="$today" \                               #
              #       >       '{                                                     #
              #       >           gsub(/:/," ",$0)                                   #
              #       >           gsub(/_/," ",$0)                                   #
              #       >           if (match($0,today))                               #
              #       >              $0 = $0"\t  **HOLIDAY**"                        #
              #       >           print $0                                           #
              #       >        }'                                                    #
              #       >                                                              #
              #       >   #------------------------------------------------------#   #
              #       >   # Business day reporting: 1st, next-to-last, and last. #   #
              #       >   #------------------------------------------------------#   #
              #       >   bizday=`$holiday_cmd -b 1 $holiday_file`                   #
              #       >   if [ `date +\%Y\%m\%d` = $bizday ]; then                   #
              #       >      echo "Today is the first business day of the month."    #
              #       >   fi                                                         #
              #       >                                                              #
              #       >   bizday=`$holiday_cmd -b -1 $holiday_file`                  #
              #       >   if [ `date +\%Y\%m\%d` = $bizday ]; then                   #
              #       >      echo "Today is the next-to-last business day."          #
              #       >   fi                                                         #
              #       >                                                              #
              #       >   bizday=`$holiday_cmd -b last $holiday_file`                #
              #       >   if [ `date +\%Y\%m\%d` = $bizday ]; then                   #
              #       >      echo "Today is the last business day of the month."     #
              #       >   fi                                                         #
              #       >                                                              #
              #       >   #------------------------------------------------------#   #
              #       >   # See if today is a business day at all.               #   #
              #       >   #------------------------------------------------------#   #
              #       >   $holiday_cmd -B $holiday_file                              #
              #       >   if [ $? -eq 1 ]; then                                      #
              #       >      echo "Today is a business day--get crackin'."           #
              #       >   else                                                       #
              #       >      echo "Today is NOT a business day--have fun."           #
              #       >   fi                                                         #
              #       >                                                              #
              #       >   #------------------------------------------------------#   #
              #       >   # First Monday and last Sunday of the current month.   #   #
              #       >   #------------------------------------------------------#   #
              #       >   fst_monday=`$holiday_cmd -d 1.Mon`                         #
              #       >   fst_monday=`$holiday_cmd -d 1.1`    # Alternative syntax   #
              #       >   lst_sunday=`$holiday_cmd -d last.Sun`                      #
              #       >   lst_sunday=`$holiday_cmd -d last.0` # Alternative syntax   #
              #       >                                                              #
              #       >   #------------------------------------------------------#   #
              #       >   # Falklands Day Light Savings Dates.                   #   #
              #       >   #------------------------------------------------------#   #
              #       >   Falk_DST=`$holiday_cmd -d 1.0.8 -m 9` # DST begins         #
              #       >   Falk_ST=` $holiday_cmd -d 1.0.6 -m 4` # Return to ST       #
              #       >                                                              #
              #       >   #------------------------------------------------------#   #
              #       >   # See if today is the 1st Monday of the month and      #   #
              #       >   # if it is the first business day of the month (the    #   #
              #       >   # business day example uses the default holidays file, #   #
              #       >   # /usr/local/bin/holidays (assuming the file exists).  #   #
              #       >   #------------------------------------------------------#   #
              #       >   $holiday_cmd -t -d 1.Mon || echo "Today is 1st Monday"     #
              #       >   $holiday_cmd -t -b 1 || echo "Today is 1st Business day"   #
              #       >                                                              #
              #       >   #------------------------------------------------------#   #
              #       >   # Find the date range wherein the 5th bizday falls-    #   #
              #       >   # --great for setting cron date range, like this.      #   #
              #       >   #                                                      #   #
              #       >   #   00 01 5-7 * * `/usr/local/bin/holidays.awk -- \    #   #
              #       >   #    -b 5 -t` || some_process > some_process.out 2>&1  #   #
              #       >   #                                                      #   #
              #       >   # Here again, by not specifying a holidays file,       #   #
              #       >   # we use the default, /usr/local/bin/holidays.         #   #
              #       >   #------------------------------------------------------#   #
              #       >   years="00 01 02 03 04 05 06 07 08 09"                      #
              #       >   years="$years 10 11 12 13 14 15 16 17 18 19"               #
              #       >   years="$years 20 21 22 23 24 25"                           #
              #       >   for n in $years                                            #
              #       >   do                                                         #
              #       >      /usr/local/bin/holidays.awk -- -y 20$n -b 5             #
              #       >   done                                                       #
              #                                                                      #
              #                                                                      #
              #     Credits: 1. The algorithms used here are from Marcos J. Montes   #
              #                 (http://www.smart.net/~mmontes/ushols.html#ALG).     #
              #                 Montes, in turn, credits Claus Tondering's work      #
              #                 (http://www.tondering.dk/claus/calendar.html),       #
              #                 for the algorithm and Timothy Barmann and Bobby      #
              #                 Cossum for their contributions in simplifying the    #
              #                 equations used.  Those gentlemen did the really      #
              #                 hard work.                                           #
              #                                                                      #
              #              2. The On-or-After (OoA) capability available in the    #
              #                 holidays file and with the -d option was requested   #
              #                 by Kevin Marshall who also provided a critical part  #
              #                 of the code to accomplish this.  This he did so he   #
              #                 could determine, for example, daylight saving begin  #
              #                 and end dates for the Falkland islands.              #
              #                                                                      #
              #                                                                      #
              #  Exit Codes: For all except business day (-b) and weekday (-d)       #
              #              options...                                              #
              #                                                                      #
              #                 Zero    = Normal   | Success                         #
              #                 Nonzero = Abnormal | Failure                         #
              #                                                                      #
              #              With business day (-b) and weekday (-d) options ...     #
              #                                                                      #
              #                 Nonzero = The day of the month on which the weekday  #
              #                           weekday business day falls.                #
              #                 Zero    = Abnormal | Failure                         #
              #                                                                      #
              #              With business day (-b) and weekday (-d) options used    #
              #              in conjunction with "today is" (-t) ...                 #
              #                                                                      #
              #                 One |true  = The weekday or business day IS today.   #
              #                 Zero|false = The day of the month on which the       #
              #                              weekday or business day falls           #
              #                              is NOT today.                           #
              #                                                                      #
              #              In addition to descriptive error messages (something    #
              #              rare in AWK) each error exit has a different status     #
              #              to assist in locating the source of the error.          #
              #                                                                      #
              #                                                                      #
              #       Notes: 1. I could have called my dateplus.c to provide the     #
              #                 same functionality as dateplus() and day_of_week(),  #
              #                 but my intent was to have a single, self-contained   #
              #                 piece of code.                                       #
              #                                                                      #
              #              2. I am no mathematician.  Heck, I'm not that great     #
              #                 an Awk programmer, so there are doubtless, many      #
              #                 places where this code can be improved/simplified.   #
              #                 Feel free, therefore, to forward comments and        #
              #                 suggestions to Bob@OrlandoKuntao.com.  That said,    #
              #                 my preference is for readable/understandable code    #
              #                 over more efficient, but difficult to follow (read   #
              #                 obfuscated) code since readable code (even if less   #
              #                 efficient) makes maintenance much less a chore.      #
              #                                                                      #
              #                                                                      #
              #    Modified: 2011-12-02 Bob Orlando                                  #
              #                 v1.24 * Added usage "Example:" to documentation.     #
              #                                                                      #
              #              2005-10-25 Bob Orlando                                  #
              #                 v1.23 * Add an "on or after" extension used in our   #
              #                         holidays file to the -d option (i.e.         #
              #                         -d "N.D.OnOrA") allowing the user to specify #
              #                         an occurrence or week number (N) and week    #
              #                         day (D) within that week, AND also indicate  #
              #                         the date must fall on or after a given day   #
              #                         of the month (OnOrA).                        #
              #                                                                      #
              #----------------------------------------------------------------------#
            
Artificial Intelligence is no match for natural stupidity.
©Copyright Bob Orlando, 2003-2011
All rights reserved.
http://www.OrlandoKuntao.com
E-mail: Bob@OrlandoKuntao.com
Last update: Dec. 2, 2011
by Bob Orlando