I was in another forum and saw someone talk about manually entering holidays into their system, and thought it might be interesting to try to code up something that comes up with holidays, so I came up with this proof-of-concept that something along those lines could be done. Hopefully it helps out someone.
About the only thing that's missing is adjusting for workdays if a holiday comes up on a Saturday or a Sunday, but that can be easily handled by calling 2000-Zeller and then adjusting the day forward or backward.
About the only thing that's missing is adjusting for workdays if a holiday comes up on a Saturday or a Sunday, but that can be easily handled by calling 2000-Zeller and then adjusting the day forward or backward.
Code:
IDENTIFICATION DIVISION.
PROGRAM-ID. HOLIDAY.
* This program lists all holidays for the year given in input.
* RULES FOR HOLIDAYS.
*
* WRITTEN AND COPYRIGHTED FOR GENERAL DISTRIBUTION BY
* "GLENN9999 AT tek-tips.COM". ANY USE OF THIS CODE MUST
* INCLUDE THESE THREE LINES WITHIN THEM.
*
* 1) New Year's Day is every January 1.
* 2) Martin Luther King Day is the third Monday in January.
* 3) President's Day is the third Monday in February.
* 4) Easter is ...
* 5) Memorial Day is the last Monday in May.
* 6) Independence Day is every July 4.
* 7) Labor Day is the first monday in September.
* 8) Columbus Day is the second Monday in October.
* 9) Veteran's Day is November 11.
* 10) Thanksgiving is the fourth Thursday in November.
* 11) Christmas is December 25.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 PROCESSING-VARIABLES.
04 YEAR-INPUT PIC S9(4) COMP-5.
04 ZIN-MONTH PIC S9(4) COMP-5.
04 ZIN-YEAR PIC S9(4) COMP-5.
04 ZIN-CENTURY PIC S9(4) COMP-5.
04 ZIN-DOW PIC S9(4) COMP-5.
04 ZIN-DAY PIC S9(4) COMP-5.
04 ZIN-TEMP PIC S9(4) COMP-5.
04 EST-N PIC S9(4) COMP-5.
04 EST-D PIC S9(4) COMP-5.
04 EST-K PIC S9(4) COMP-5.
04 EST-I PIC S9(4) COMP-5.
04 EST-J PIC S9(4) COMP-5.
04 EST-L PIC S9(4) COMP-5.
01 OUTPUT-VARIABLES.
04 OUTPUT-DATA.
08 PIC X(32) VALUE "NEW YEAR'S DAY".
08 PIC X(10) VALUE " / / ".
08 PIC X(32)
VALUE "MARTIN LUTHER KING DAY".
08 PIC X(10) VALUE " / / ".
08 PIC X(32) VALUE "PRESIDENT'S DAY".
08 PIC X(10) VALUE " / / ".
08 PIC X(32) VALUE "EASTER".
08 PIC X(10) VALUE " / / ".
08 PIC X(32) VALUE "MEMORIAL DAY".
08 PIC X(10) VALUE " / / ".
08 PIC X(32) VALUE "INDEPENDENCE DAY".
08 PIC X(10) VALUE " / / ".
08 PIC X(32) VALUE "LABOR DAY".
08 PIC X(10) VALUE " / / ".
08 PIC X(32) VALUE "COLUMBUS DAY".
08 PIC X(10) VALUE " / / ".
08 PIC X(32) VALUE "VETERAN'S DAY".
08 PIC X(10) VALUE " / / ".
08 PIC X(32) VALUE "THANKSGIVING".
08 PIC X(10) VALUE " / / ".
08 PIC X(32) VALUE "CHRISTMAS".
08 PIC X(10) VALUE " / / ".
04 OUTPUT-TABLE REDEFINES OUTPUT-DATA
OCCURS 11 TIMES
INDEXED BY OUT-NDX.
08 FILLER PIC X(32).
08 OUT-MONTH PIC 99.
08 FILLER PIC X.
08 OUT-DAY PIC 99.
08 FILLER PIC X.
08 OUT-YEAR PIC 9999.
PROCEDURE DIVISION.
0000-MAIN SECTION.
MOVE 1 TO ZIN-DAY.
DISPLAY "ENTER A YEAR."
ACCEPT YEAR-INPUT.
PERFORM 1000-PROCESS-DATA.
PERFORM VARYING OUT-NDX FROM 1 BY 1
UNTIL OUT-NDX > 11
DISPLAY OUTPUT-TABLE (OUT-NDX)
END-PERFORM.
GOBACK.
1000-PROCESS-DATA SECTION.
PERFORM 1001-NEW-YEARS-DAY.
PERFORM 1002-MLKDAY.
PERFORM 1003-PRES-DAY.
PERFORM 1004-EASTER.
PERFORM 1005-MEM-DAY.
PERFORM 1006-INDEP-DAY.
PERFORM 1007-LABORDAY.
PERFORM 1008-COLUMBUSDAY.
PERFORM 1009-VETERANSDAY.
PERFORM 1010-THANKSGIVING.
PERFORM 1011-CHRISTMAS.
1001-NEW-YEARS-DAY SECTION.
* NEW YEAR'S DAY
SET OUT-NDX TO 1.
MOVE YEAR-INPUT TO OUT-YEAR (OUT-NDX).
MOVE 1 TO OUT-MONTH (OUT-NDX).
MOVE 1 TO OUT-DAY (OUT-NDX).
1002-MLKDAY SECTION.
SET OUT-NDX TO 2.
* MARTIN LUTHER KING DAY
MOVE 1 TO OUT-MONTH (OUT-NDX) ZIN-MONTH.
MOVE YEAR-INPUT TO ZIN-YEAR.
PERFORM 2000-ZELLER.
* ADJUST TO THE FIRST MONDAY (1)
IF ZIN-DOW < 1
COMPUTE ZIN-TEMP = 1 - ZIN-DOW
ELSE
COMPUTE ZIN-TEMP = 7 - ZIN-DOW + 1
END-IF.
* ADJUST TO THE THIRD MONDAY
COMPUTE OUT-DAY (OUT-NDX) = ZIN-DAY + ZIN-TEMP + (2 * 7).
MOVE YEAR-INPUT TO OUT-YEAR (OUT-NDX).
1003-PRES-DAY SECTION.
SET OUT-NDX TO 3.
* PRESIDENTS DAY
MOVE 2 TO OUT-MONTH (OUT-NDX) ZIN-MONTH.
MOVE YEAR-INPUT TO ZIN-YEAR.
PERFORM 2000-ZELLER.
* ADJUST TO THE FIRST MONDAY (1)
IF ZIN-DOW < 1
COMPUTE ZIN-TEMP = 1 - ZIN-DOW
ELSE
COMPUTE ZIN-TEMP = 7 - ZIN-DOW + 1
END-IF.
* ADJUST TO THE THIRD MONDAY
COMPUTE OUT-DAY (OUT-NDX) = ZIN-DAY + ZIN-TEMP + (2 * 7).
MOVE YEAR-INPUT TO OUT-YEAR (OUT-NDX).
1004-EASTER SECTION.
SET OUT-NDX TO 4.
MOVE YEAR-INPUT TO ZIN-YEAR OUT-YEAR (OUT-NDX).
PERFORM 3000-EASTER.
MOVE ZIN-MONTH TO OUT-MONTH (OUT-NDX).
MOVE EST-D TO OUT-DAY (OUT-NDX).
1005-MEM-DAY SECTION.
SET OUT-NDX TO 5.
* MEMORIAL DAY IS LAST MONDAY IN MAY, SO WE NEED TO FIND JUNE 1.
MOVE 6 TO ZIN-MONTH.
MOVE YEAR-INPUT TO ZIN-YEAR.
PERFORM 2000-ZELLER.
* ADJUST TO THE PREVIOUS MONDAY (1)
IF ZIN-DOW > 1
COMPUTE ZIN-TEMP = ZIN-DOW - 1
ELSE
COMPUTE ZIN-TEMP = 7 - ZIN-DOW - 1
END-IF.
* ADJUST TO THE PREVIOUS MONDAY (IN MAY)
COMPUTE OUT-DAY (OUT-NDX) = 31 - ZIN-TEMP + 1.
MOVE 5 TO OUT-MONTH (OUT-NDX).
MOVE YEAR-INPUT TO OUT-YEAR (OUT-NDX).
1006-INDEP-DAY SECTION.
* INDEPENDENCE DAY
SET OUT-NDX TO 6.
MOVE YEAR-INPUT TO OUT-YEAR (OUT-NDX).
MOVE 7 TO OUT-MONTH (OUT-NDX).
MOVE 4 TO OUT-DAY (OUT-NDX).
1007-LABORDAY SECTION.
SET OUT-NDX TO 7.
* LABOR DAY
MOVE 9 TO OUT-MONTH (OUT-NDX) ZIN-MONTH.
MOVE YEAR-INPUT TO ZIN-YEAR.
PERFORM 2000-ZELLER.
* ADJUST TO THE FIRST MONDAY (1)
IF ZIN-DOW < 1
COMPUTE ZIN-TEMP = 1 - ZIN-DOW
ELSE
COMPUTE ZIN-TEMP = 7 - ZIN-DOW + 1
END-IF.
* ADJUST TO THE FIRST MONDAY
COMPUTE OUT-DAY (OUT-NDX) = ZIN-DAY + ZIN-TEMP.
MOVE YEAR-INPUT TO OUT-YEAR (OUT-NDX).
1008-COLUMBUSDAY SECTION.
SET OUT-NDX TO 8.
* COLUMBUS DAY
MOVE 10 TO OUT-MONTH (OUT-NDX) ZIN-MONTH.
MOVE YEAR-INPUT TO ZIN-YEAR.
PERFORM 2000-ZELLER.
* ADJUST TO THE FIRST MONDAY (1)
IF ZIN-DOW < 1
COMPUTE ZIN-TEMP = 1 - ZIN-DOW
ELSE
COMPUTE ZIN-TEMP = 7 - ZIN-DOW + 1
END-IF.
* ADJUST TO THE SECOND MONDAY
COMPUTE OUT-DAY (OUT-NDX) = ZIN-DAY + ZIN-TEMP + (1 * 7).
MOVE YEAR-INPUT TO OUT-YEAR (OUT-NDX).
1009-VETERANSDAY SECTION.
* VETERANS DAY
SET OUT-NDX TO 9.
MOVE YEAR-INPUT TO OUT-YEAR (OUT-NDX).
MOVE 11 TO OUT-MONTH (OUT-NDX).
MOVE 11 TO OUT-DAY (OUT-NDX).
1010-THANKSGIVING SECTION.
SET OUT-NDX TO 10.
* THANKSGIVING
MOVE 11 TO OUT-MONTH (OUT-NDX) ZIN-MONTH.
MOVE YEAR-INPUT TO ZIN-YEAR.
PERFORM 2000-ZELLER.
* ADJUST TO THE FIRST THURSDAY (4)
IF ZIN-DOW < 4
COMPUTE ZIN-TEMP = 4 - ZIN-DOW
ELSE
COMPUTE ZIN-TEMP = 7 - ZIN-DOW + 4
END-IF.
* ADJUST TO THE FOURTH MONDAY
COMPUTE OUT-DAY (OUT-NDX) = ZIN-DAY + ZIN-TEMP + (3 * 7).
MOVE YEAR-INPUT TO OUT-YEAR (OUT-NDX).
1011-CHRISTMAS SECTION.
* CHRISTMAS DAY
SET OUT-NDX TO 11.
MOVE YEAR-INPUT TO OUT-YEAR (OUT-NDX).
MOVE 12 TO OUT-MONTH (OUT-NDX).
MOVE 25 TO OUT-DAY (OUT-NDX).
2000-ZELLER SECTION.
* An implementation of Zellers Congruence - Provides the
* first day of the month passed to ZIN-MONTH, RETURNS DAY OF
* WEEK IN ZIN-DOW..
* [URL unfurl="true"]http://www.adaic.org/docs/craft/html/ch04.htm[/URL]
* ZIN-DOW IS 0 = SUNDAY 1 = MONDAY 2 = TUESDAY 3 = WEDNESDAY
* 4 = THURSDAY 5 = FRIDAY 6 = SATURDAY
IF ZIN-MONTH < 3 THEN
SUBTRACT 1 FROM ZIN-YEAR
ADD 10 TO ZIN-MONTH
ELSE
SUBTRACT 2 FROM ZIN-MONTH
END-IF.
DIVIDE ZIN-YEAR BY 100 GIVING ZIN-CENTURY REMAINDER ZIN-YEAR.
COMPUTE ZIN-TEMP = (26 * ZIN-MONTH - 2) / 10.
COMPUTE ZIN-TEMP = ZIN-TEMP + ZIN-DAY + ZIN-YEAR.
COMPUTE ZIN-TEMP = ZIN-TEMP + (ZIN-YEAR / 4) + (ZIN-CENTURY / 4).
COMPUTE ZIN-TEMP = ZIN-TEMP - (2 * ZIN-CENTURY).
DIVIDE ZIN-TEMP BY 7 GIVING ZIN-TEMP REMAINDER ZIN-DOW.
IF ZIN-DOW < 0
ADD 7 TO ZIN-DOW
END-IF.
3000-EASTER SECTION.
*The algorithm uses the year, y, to give the month, m, and day,
* d, of Easter. The symbol * means multiply. Please note the
* following: This is an integer calculation. All variables
* are integers and all remainders from division are dropped.
* [URL unfurl="true"]http://aa.usno.navy.mil/faq/docs/easter.html[/URL]
* c = y / 100
* n = y - 19 * ( y / 19 )
* k = ( c - 17 ) / 25
* i = c - c / 4 - ( c - k ) / 3 + 19 * n + 15
* i = i - 30 * ( i / 30 )
* i = i - ( i / 28 ) * ( 1 - ( i / 28 ) * ( 29 / ( i + 1 ) )
* * ( ( 21 - n ) / 11 ) )
* j = y + y / 4 + i + 2 - c + c / 4
* j = j - 7 * ( j / 7 )
** l = i - j
* m = 3 + ( l + 40 ) / 44
* d = l + 28 - 31 * ( m / 4 )
*
COMPUTE ZIN-CENTURY = ZIN-YEAR / 100.
COMPUTE EST-N = ZIN-YEAR - 19 * (ZIN-YEAR / 19).
COMPUTE EST-K = (ZIN-CENTURY - 17) / 25.
COMPUTE EST-I = ZIN-CENTURY - (ZIN-CENTURY / 4) - (ZIN-CENTURY - EST-K) / 3.
COMPUTE EST-I = EST-I + 19 * EST-N + 15.
COMPUTE EST-I = EST-I - 30 * (EST-I / 30).
COMPUTE EST-I = EST-I - (EST-I / 28) * (1 - (EST-I / 28) * (29 / (EST-I + 1))
* ((21 - EST-N) / 11)).
COMPUTE EST-J = ZIN-YEAR + (ZIN-YEAR / 4) + EST-I + 2 - ZIN-CENTURY + (ZIN-CENTURY / 4)
COMPUTE EST-J = EST-J - 7 * (EST-J / 7)
COMPUTE EST-L = EST-I - EST-J.
COMPUTE ZIN-MONTH = 3 + (EST-L + 40) / 44.
COMPUTE EST-D = EST-L + 28 - 31 * (ZIN-MONTH / 4).