A Holiday Dates  Perl program  is also available.
                  #!/usr/bin/nawk -f
                  # SccsId[] = "@(#)holidays.awk 1.25 05/29/13 (AWK holiday calculation/reporting program)"
                  #----------------------------------------------------------------------#
                  #                            holidays.awk                              #
                  # -------------------------------------------------------------------- #
                  #                                                                      #
                  #   Copyright (c) 2003-2013 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 :-))                           #
                    # -------------------------------------------------------------- #
                    # 20130529.091642: Updates subsequent to this 2003-07-04 (v1.3)  #
                    # needed test, makes the following two (now commented out) lines #
                    #                                                                #
                  # dow = day_of_week(YYYY,MM,mm_days)
                  # if (dow == 0) dow = 7
                    #                                                                #
                    # ... completely unnecessary.                                    #
                    #----------------------------------------------------------------#

                    #----------------------------------------------------------------#
                    # 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   #
                  #                                wanted 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: 2013-05-29 Bob Orlando                                  #
                  #                 v1.25 * Commented out two lines that were part of    #
                  #                         v1.03 modification to holiday_date function  #
                  #                         because subsequent updates to that same      #
                  #                         function made those two lines completely     #
                  #                         unnecessary.                                 #
                  #                                                                      #
                  #              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-2016
All rights reserved.
http://www.OrlandoKuntao.com
E-mail: Bob@OrlandoKuntao.com
Last update:  Feb. 2, 2016
by Bob Orlando