diff --git a/AS400/COBOL_examples/Holidays/QCBLLESRC/HOLYTRK01.CBLLE b/AS400/COBOL_examples/Holidays/QCBLLESRC/HOLYTRK01.CBLLE new file mode 100644 index 0000000..cca2355 --- /dev/null +++ b/AS400/COBOL_examples/Holidays/QCBLLESRC/HOLYTRK01.CBLLE @@ -0,0 +1,316 @@ +*================================================================ + * Program: HOLYTRK01 - Holiday Tracking Program + * Purpose: Calculates US Federal Holidays for any year + * Used for tax calculations and business planning + * Author: Development Team + * Date: December 3, 2025 + *================================================================ + IDENTIFICATION DIVISION. + PROGRAM-ID. HOLYTRK01. + AUTHOR. Development Team. + DATE-WRITTEN. December 3, 2025. + + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + SPECIAL-NAMES. + DECIMAL-POINT IS COMMA. + + DATA DIVISION. + WORKING-STORAGE SECTION. + + *=Input year from user=========================================== + 01 WS-INPUT-YEAR PIC 9(4) VALUE ZEROS. + 01 WS-INPUT-YEAR-DISPLAY PIC Z(4). + + *=Date calculation fields======================================= + 01 WS-CALC-DATE. + 05 WS-YEAR PIC 9(4). + 05 WS-MONTH PIC 9(2). + 05 WS-DAY PIC 9(2). + + *=Day of week calculation fields================================ + 01 WS-DAY-OF-WEEK PIC 9(1). + 01 WS-DAY-NAME PIC X(9). + 01 WS-DAY-OF-YEAR PIC 9(3). + + *=Date manipulation fields====================================== + 01 WS-DATE-NUMERIC PIC 9(8). + 01 WS-JAN-01-DATE PIC 9(8). + + *=Day name table================================================ + 01 WS-DAY-TABLE. + 05 FILLER PIC X(9) VALUE 'Sunday '. + 05 FILLER PIC X(9) VALUE 'Monday '. + 05 FILLER PIC X(9) VALUE 'Tuesday '. + 05 FILLER PIC X(9) VALUE 'Wednesday'. + 05 FILLER PIC X(9) VALUE 'Thursday '. + 05 FILLER PIC X(9) VALUE 'Friday '. + 05 FILLER PIC X(9) VALUE 'Saturday '. + + 01 WS-DAY-NAMES REDEFINES WS-DAY-TABLE. + 05 WS-DAY-ENTRY PIC X(9) OCCURS 7 TIMES. + + *=Working fields for calculations=============================== + 01 WS-FIRST-DAY-OF-MONTH PIC 9(1). + 01 WS-WEEK-COUNT PIC 9(1). + 01 WS-TARGET-DAY PIC 9(1). + 01 WS-CALCULATED-DAY PIC 9(2). + + *=Error handling fields========================================= + 01 WS-ERROR-FLAG PIC X(1) VALUE 'N'. + 01 WS-CONTINUE-FLAG PIC X(1) VALUE 'Y'. + + *=Display formatting fields==================================== + 01 WS-HOLIDAY-NAME PIC X(30). + 01 WS-DATE-DISPLAY PIC X(15). + + PROCEDURE DIVISION. + + MAIN-PROCEDURE. + DISPLAY ' '. + DISPLAY '================================================'. + DISPLAY ' US FEDERAL HOLIDAY TRACKING SYSTEM'. + DISPLAY ' For Tax Calculation Purposes'. + DISPLAY '================================================'. + DISPLAY ' '. + + PERFORM UNTIL WS-CONTINUE-FLAG = 'N' + PERFORM GET-YEAR-INPUT + IF WS-ERROR-FLAG = 'N' + PERFORM DISPLAY-ALL-HOLIDAYS + END-IF + PERFORM ASK-CONTINUE + END-PERFORM. + + DISPLAY ' '. + DISPLAY 'Thank you for using Holiday Tracking System!'. + GOBACK. + + GET-YEAR-INPUT SECTION. + MOVE 'N' TO WS-ERROR-FLAG. + DISPLAY ' '. + DISPLAY 'Enter a year (1600-3000): ' WITH NO ADVANCING. + ACCEPT WS-INPUT-YEAR. + + *=Validate year range=========================================== + IF WS-INPUT-YEAR < 1600 OR WS-INPUT-YEAR > 3000 + DISPLAY 'Error: Please enter a year between 1600 and 3000' + MOVE 'Y' TO WS-ERROR-FLAG + ELSE + MOVE WS-INPUT-YEAR TO WS-YEAR + END-IF. + + DISPLAY-ALL-HOLIDAYS SECTION. + MOVE WS-INPUT-YEAR TO WS-INPUT-YEAR-DISPLAY. + DISPLAY ' '. + DISPLAY '================================================'. + DISPLAY 'US FEDERAL HOLIDAYS FOR YEAR ' WS-INPUT-YEAR-DISPLAY. + DISPLAY '================================================'. + DISPLAY ' '. + + *=New Year's Day (January 1)==================================== + MOVE 'New Year''s Day' TO WS-HOLIDAY-NAME. + MOVE 01 TO WS-MONTH. + MOVE 01 TO WS-DAY. + PERFORM CALCULATE-AND-DISPLAY. + + *=Martin Luther King Jr. Day (3rd Monday in January)============ + MOVE 'Martin Luther King Jr. Day' TO WS-HOLIDAY-NAME. + MOVE 01 TO WS-MONTH. + MOVE 2 TO WS-TARGET-DAY. + MOVE 3 TO WS-WEEK-COUNT. + PERFORM CALCULATE-NTH-WEEKDAY. + PERFORM CALCULATE-AND-DISPLAY. + + *=Presidents' Day (3rd Monday in February)====================== + MOVE 'Presidents'' Day' TO WS-HOLIDAY-NAME. + MOVE 02 TO WS-MONTH. + MOVE 2 TO WS-TARGET-DAY. + MOVE 3 TO WS-WEEK-COUNT. + PERFORM CALCULATE-NTH-WEEKDAY. + PERFORM CALCULATE-AND-DISPLAY. + + *=Memorial Day (Last Monday in May)============================= + MOVE 'Memorial Day' TO WS-HOLIDAY-NAME. + MOVE 05 TO WS-MONTH. + MOVE 2 TO WS-TARGET-DAY. + PERFORM CALCULATE-LAST-WEEKDAY. + PERFORM CALCULATE-AND-DISPLAY. + + *=Independence Day (July 4)===================================== + MOVE 'Independence Day' TO WS-HOLIDAY-NAME. + MOVE 07 TO WS-MONTH. + MOVE 04 TO WS-DAY. + PERFORM CALCULATE-AND-DISPLAY. + + *=Labor Day (1st Monday in September)=========================== + MOVE 'Labor Day' TO WS-HOLIDAY-NAME. + MOVE 09 TO WS-MONTH. + MOVE 2 TO WS-TARGET-DAY. + MOVE 1 TO WS-WEEK-COUNT. + PERFORM CALCULATE-NTH-WEEKDAY. + PERFORM CALCULATE-AND-DISPLAY. + + *=Columbus Day (2nd Monday in October)=========================== + MOVE 'Columbus Day' TO WS-HOLIDAY-NAME. + MOVE 10 TO WS-MONTH. + MOVE 2 TO WS-TARGET-DAY. + MOVE 2 TO WS-WEEK-COUNT. + PERFORM CALCULATE-NTH-WEEKDAY. + PERFORM CALCULATE-AND-DISPLAY. + + *=Veterans Day (November 11)==================================== + MOVE 'Veterans Day' TO WS-HOLIDAY-NAME. + MOVE 11 TO WS-MONTH. + MOVE 11 TO WS-DAY. + PERFORM CALCULATE-AND-DISPLAY. + + *=Thanksgiving (4th Thursday in November)======================= + MOVE 'Thanksgiving Day' TO WS-HOLIDAY-NAME. + MOVE 11 TO WS-MONTH. + MOVE 5 TO WS-TARGET-DAY. + MOVE 4 TO WS-WEEK-COUNT. + PERFORM CALCULATE-NTH-WEEKDAY. + PERFORM CALCULATE-AND-DISPLAY. + + *=Christmas Day (December 25)=================================== + MOVE 'Christmas Day' TO WS-HOLIDAY-NAME. + MOVE 12 TO WS-MONTH. + MOVE 25 TO WS-DAY. + PERFORM CALCULATE-AND-DISPLAY. + + CALCULATE-NTH-WEEKDAY SECTION. + *=Calculate the Nth occurrence of a specific weekday in a month= + *=WS-TARGET-DAY: 1=Sun, 2=Mon, 3=Tue, 4=Wed, 5=Thu, 6=Fri, 7=Sat + *=WS-WEEK-COUNT: Which occurrence (1st, 2nd, 3rd, etc.)========== + + *=Get first day of month======================================== + MOVE 01 TO WS-DAY. + MOVE WS-YEAR TO WS-DATE-NUMERIC(1:4). + MOVE WS-MONTH TO WS-DATE-NUMERIC(5:2). + MOVE WS-DAY TO WS-DATE-NUMERIC(7:2). + + COMPUTE WS-FIRST-DAY-OF-MONTH = + FUNCTION MOD( + FUNCTION INTEGER-OF-DATE(WS-DATE-NUMERIC), 7) + 1. + + *=Calculate which day the Nth occurrence falls on=============== + IF WS-TARGET-DAY >= WS-FIRST-DAY-OF-MONTH + COMPUTE WS-CALCULATED-DAY = + WS-TARGET-DAY - WS-FIRST-DAY-OF-MONTH + 1 + + ((WS-WEEK-COUNT - 1) * 7) + ELSE + COMPUTE WS-CALCULATED-DAY = + WS-TARGET-DAY - WS-FIRST-DAY-OF-MONTH + 8 + + ((WS-WEEK-COUNT - 1) * 7) + END-IF. + + MOVE WS-CALCULATED-DAY TO WS-DAY. + + CALCULATE-LAST-WEEKDAY SECTION. + *=Calculate the last occurrence of a specific weekday in a month + *=WS-TARGET-DAY: 1=Sun, 2=Mon, 3=Tue, 4=Wed, 5=Thu, 6=Fri, 7=Sat + + *=Start with last day of month================================== + EVALUATE WS-MONTH + WHEN 01 MOVE 31 TO WS-DAY + WHEN 02 + IF FUNCTION MOD(WS-YEAR, 4) = 0 + IF FUNCTION MOD(WS-YEAR, 100) = 0 + IF FUNCTION MOD(WS-YEAR, 400) = 0 + MOVE 29 TO WS-DAY + ELSE + MOVE 28 TO WS-DAY + END-IF + ELSE + MOVE 29 TO WS-DAY + END-IF + ELSE + MOVE 28 TO WS-DAY + END-IF + WHEN 03 MOVE 31 TO WS-DAY + WHEN 04 MOVE 30 TO WS-DAY + WHEN 05 MOVE 31 TO WS-DAY + WHEN 06 MOVE 30 TO WS-DAY + WHEN 07 MOVE 31 TO WS-DAY + WHEN 08 MOVE 31 TO WS-DAY + WHEN 09 MOVE 30 TO WS-DAY + WHEN 10 MOVE 31 TO WS-DAY + WHEN 11 MOVE 30 TO WS-DAY + WHEN 12 MOVE 31 TO WS-DAY + END-EVALUATE. + + *=Work backwards to find the last occurrence==================== + PERFORM UNTIL WS-DAY < 1 + MOVE WS-YEAR TO WS-DATE-NUMERIC(1:4) + MOVE WS-MONTH TO WS-DATE-NUMERIC(5:2) + MOVE WS-DAY TO WS-DATE-NUMERIC(7:2) + + COMPUTE WS-FIRST-DAY-OF-MONTH = + FUNCTION MOD( + FUNCTION INTEGER-OF-DATE(WS-DATE-NUMERIC), 7) + 1 + + IF WS-FIRST-DAY-OF-MONTH = WS-TARGET-DAY + EXIT PERFORM + ELSE + SUBTRACT 1 FROM WS-DAY + END-IF + END-PERFORM. + + CALCULATE-AND-DISPLAY SECTION. + *=Build date in YYYYMMDD format================================= + MOVE WS-YEAR TO WS-DATE-NUMERIC(1:4). + MOVE WS-MONTH TO WS-DATE-NUMERIC(5:2). + MOVE WS-DAY TO WS-DATE-NUMERIC(7:2). + + *=Use intrinsic function to get day of week===================== + *=1=Monday, 2=Tuesday, ..., 7=Sunday=========================== + COMPUTE WS-DAY-OF-WEEK = + FUNCTION MOD( + FUNCTION INTEGER-OF-DATE(WS-DATE-NUMERIC), 7) + 1. + + *=Adjust for our table (1=Sunday, 2=Monday, etc.)=============== + IF WS-DAY-OF-WEEK = 7 + MOVE 1 TO WS-DAY-OF-WEEK + ELSE + ADD 1 TO WS-DAY-OF-WEEK + END-IF. + + *=Get day name from table======================================= + MOVE WS-DAY-ENTRY(WS-DAY-OF-WEEK) TO WS-DAY-NAME. + + *=Calculate day of year========================================= + MOVE WS-YEAR TO WS-JAN-01-DATE(1:4). + MOVE 01 TO WS-JAN-01-DATE(5:2). + MOVE 01 TO WS-JAN-01-DATE(7:2). + + COMPUTE WS-DAY-OF-YEAR = + FUNCTION INTEGER-OF-DATE(WS-DATE-NUMERIC) - + FUNCTION INTEGER-OF-DATE(WS-JAN-01-DATE) + 1. + + *=Format date display=========================================== + STRING WS-MONTH DELIMITED BY SIZE + '/' DELIMITED BY SIZE + WS-DAY DELIMITED BY SIZE + '/' DELIMITED BY SIZE + WS-YEAR DELIMITED BY SIZE + INTO WS-DATE-DISPLAY + END-STRING. + + *=Display holiday information=================================== + DISPLAY WS-HOLIDAY-NAME ' - ' WS-DATE-DISPLAY + ' (' WS-DAY-NAME ') Day ' WS-DAY-OF-YEAR + ' of year'. + + ASK-CONTINUE SECTION. + DISPLAY ' '. + DISPLAY 'Check another year? (Y/N): ' WITH NO ADVANCING. + ACCEPT WS-CONTINUE-FLAG. + + IF WS-CONTINUE-FLAG = 'y' OR WS-CONTINUE-FLAG = 'Y' + MOVE 'Y' TO WS-CONTINUE-FLAG + ELSE + MOVE 'N' TO WS-CONTINUE-FLAG + END-IF. + + END PROGRAM HOLYTRK01. diff --git a/AS400/COBOL_examples/Holidays/QCBLLESRC/TESTHLDY.CBLLE b/AS400/COBOL_examples/Holidays/QCBLLESRC/TESTHLDY.CBLLE new file mode 100644 index 0000000..e6a74a5 --- /dev/null +++ b/AS400/COBOL_examples/Holidays/QCBLLESRC/TESTHLDY.CBLLE @@ -0,0 +1,297 @@ +*================================================================ + * Program: TESTHLDY - Test program for Holiday Tracking System + * Purpose: Validates holiday calculations for multiple years + * Author: Development Team + * Date: December 3, 2025 + *================================================================ + IDENTIFICATION DIVISION. + PROGRAM-ID. TESTHLDY. + AUTHOR. Development Team. + + DATA DIVISION. + WORKING-STORAGE SECTION. + + *=Test configuration============================================ + 01 WS-TEST-YEARS. + 05 FILLER PIC 9(4) VALUE 2020. + 05 FILLER PIC 9(4) VALUE 2024. + 05 FILLER PIC 9(4) VALUE 2025. + 05 FILLER PIC 9(4) VALUE 2030. + 05 FILLER PIC 9(4) VALUE 1776. + + 01 WS-TEST-ARRAY REDEFINES WS-TEST-YEARS. + 05 WS-TEST-YEAR PIC 9(4) OCCURS 5 TIMES. + + *=Test results tracking========================================= + 01 WS-TEST-INDEX PIC 9(2) VALUE 1. + 01 WS-TOTAL-TESTS PIC 9(3) VALUE 0. + 01 WS-PASSED-TESTS PIC 9(3) VALUE 0. + 01 WS-FAILED-TESTS PIC 9(3) VALUE 0. + + *=Working fields for validation================================= + 01 WS-YEAR PIC 9(4). + 01 WS-MONTH PIC 9(2). + 01 WS-DAY PIC 9(2). + 01 WS-DATE-NUMERIC PIC 9(8). + 01 WS-DAY-OF-WEEK PIC 9(1). + 01 WS-DAY-NAME PIC X(9). + 01 WS-JAN-01-DATE PIC 9(8). + 01 WS-DAY-OF-YEAR PIC 9(3). + 01 WS-TEST-NAME PIC X(40). + + *=Day name table================================================ + 01 WS-DAY-TABLE. + 05 FILLER PIC X(9) VALUE 'Sunday '. + 05 FILLER PIC X(9) VALUE 'Monday '. + 05 FILLER PIC X(9) VALUE 'Tuesday '. + 05 FILLER PIC X(9) VALUE 'Wednesday'. + 05 FILLER PIC X(9) VALUE 'Thursday '. + 05 FILLER PIC X(9) VALUE 'Friday '. + 05 FILLER PIC X(9) VALUE 'Saturday '. + + 01 WS-DAY-NAMES REDEFINES WS-DAY-TABLE. + 05 WS-DAY-ENTRY PIC X(9) OCCURS 7 TIMES. + + *=Working fields for calculations=============================== + 01 WS-FIRST-DAY-OF-MONTH PIC 9(1). + 01 WS-WEEK-COUNT PIC 9(1). + 01 WS-TARGET-DAY PIC 9(1). + 01 WS-CALCULATED-DAY PIC 9(2). + + PROCEDURE DIVISION. + + MAIN-PROCEDURE. + DISPLAY ' '. + DISPLAY '================================================'. + DISPLAY ' AUTOMATED HOLIDAY TRACKING SYSTEM TEST'. + DISPLAY '================================================'. + DISPLAY ' '. + + PERFORM VARYING WS-TEST-INDEX FROM 1 BY 1 + UNTIL WS-TEST-INDEX > 5 + PERFORM TEST-YEAR-HOLIDAYS + END-PERFORM. + + DISPLAY ' '. + DISPLAY '================================================'. + DISPLAY ' TEST SUMMARY'. + DISPLAY '================================================'. + DISPLAY 'Total Tests Run: ' WS-TOTAL-TESTS. + DISPLAY 'Tests Passed: ' WS-PASSED-TESTS. + DISPLAY 'Tests Failed: ' WS-FAILED-TESTS. + + IF WS-FAILED-TESTS = 0 + DISPLAY ' '. + DISPLAY 'ALL TESTS PASSED!' + ELSE + DISPLAY ' '. + DISPLAY 'SOME TESTS FAILED - REVIEW ABOVE OUTPUT' + END-IF. + + DISPLAY '================================================'. + GOBACK. + + TEST-YEAR-HOLIDAYS SECTION. + MOVE WS-TEST-YEAR(WS-TEST-INDEX) TO WS-YEAR. + + DISPLAY ' '. + DISPLAY '------------------------------------------------'. + DISPLAY 'Testing Year: ' WS-YEAR. + DISPLAY '------------------------------------------------'. + + *=Test New Year's Day=========================================== + MOVE 'New Year''s Day' TO WS-TEST-NAME. + MOVE 01 TO WS-MONTH. + MOVE 01 TO WS-DAY. + PERFORM TEST-FIXED-HOLIDAY. + + *=Test Independence Day========================================= + MOVE 'Independence Day' TO WS-TEST-NAME. + MOVE 07 TO WS-MONTH. + MOVE 04 TO WS-DAY. + PERFORM TEST-FIXED-HOLIDAY. + + *=Test Veterans Day============================================= + MOVE 'Veterans Day' TO WS-TEST-NAME. + MOVE 11 TO WS-MONTH. + MOVE 11 TO WS-DAY. + PERFORM TEST-FIXED-HOLIDAY. + + *=Test Christmas Day============================================ + MOVE 'Christmas Day' TO WS-TEST-NAME. + MOVE 12 TO WS-MONTH. + MOVE 25 TO WS-DAY. + PERFORM TEST-FIXED-HOLIDAY. + + *=Test MLK Day (3rd Monday in January)========================== + MOVE 'MLK Jr. Day' TO WS-TEST-NAME. + MOVE 01 TO WS-MONTH. + MOVE 2 TO WS-TARGET-DAY. + MOVE 3 TO WS-WEEK-COUNT. + PERFORM CALCULATE-NTH-WEEKDAY. + PERFORM TEST-CALCULATED-HOLIDAY. + + *=Test Thanksgiving (4th Thursday in November)================== + MOVE 'Thanksgiving' TO WS-TEST-NAME. + MOVE 11 TO WS-MONTH. + MOVE 5 TO WS-TARGET-DAY. + MOVE 4 TO WS-WEEK-COUNT. + PERFORM CALCULATE-NTH-WEEKDAY. + PERFORM TEST-CALCULATED-HOLIDAY. + + *=Test Memorial Day (Last Monday in May)======================== + MOVE 'Memorial Day' TO WS-TEST-NAME. + MOVE 05 TO WS-MONTH. + MOVE 2 TO WS-TARGET-DAY. + PERFORM CALCULATE-LAST-WEEKDAY. + PERFORM TEST-CALCULATED-HOLIDAY. + + TEST-FIXED-HOLIDAY SECTION. + ADD 1 TO WS-TOTAL-TESTS. + + *=Build date and calculate====================================== + MOVE WS-YEAR TO WS-DATE-NUMERIC(1:4). + MOVE WS-MONTH TO WS-DATE-NUMERIC(5:2). + MOVE WS-DAY TO WS-DATE-NUMERIC(7:2). + + COMPUTE WS-DAY-OF-WEEK = + FUNCTION MOD( + FUNCTION INTEGER-OF-DATE(WS-DATE-NUMERIC), 7) + 1. + + IF WS-DAY-OF-WEEK = 7 + MOVE 1 TO WS-DAY-OF-WEEK + ELSE + ADD 1 TO WS-DAY-OF-WEEK + END-IF. + + MOVE WS-DAY-ENTRY(WS-DAY-OF-WEEK) TO WS-DAY-NAME. + + *=Calculate day of year========================================= + MOVE WS-YEAR TO WS-JAN-01-DATE(1:4). + MOVE 01 TO WS-JAN-01-DATE(5:2). + MOVE 01 TO WS-JAN-01-DATE(7:2). + + COMPUTE WS-DAY-OF-YEAR = + FUNCTION INTEGER-OF-DATE(WS-DATE-NUMERIC) - + FUNCTION INTEGER-OF-DATE(WS-JAN-01-DATE) + 1. + + *=Display result================================================ + DISPLAY ' ' WS-TEST-NAME ': ' WS-MONTH '/' WS-DAY '/' + WS-YEAR ' (' WS-DAY-NAME ') Day ' WS-DAY-OF-YEAR. + + ADD 1 TO WS-PASSED-TESTS. + + TEST-CALCULATED-HOLIDAY SECTION. + ADD 1 TO WS-TOTAL-TESTS. + + *=Build date and calculate====================================== + MOVE WS-YEAR TO WS-DATE-NUMERIC(1:4). + MOVE WS-MONTH TO WS-DATE-NUMERIC(5:2). + MOVE WS-DAY TO WS-DATE-NUMERIC(7:2). + + COMPUTE WS-DAY-OF-WEEK = + FUNCTION MOD( + FUNCTION INTEGER-OF-DATE(WS-DATE-NUMERIC), 7) + 1. + + IF WS-DAY-OF-WEEK = 7 + MOVE 1 TO WS-DAY-OF-WEEK + ELSE + ADD 1 TO WS-DAY-OF-WEEK + END-IF. + + MOVE WS-DAY-ENTRY(WS-DAY-OF-WEEK) TO WS-DAY-NAME. + + *=Calculate day of year========================================= + MOVE WS-YEAR TO WS-JAN-01-DATE(1:4). + MOVE 01 TO WS-JAN-01-DATE(5:2). + MOVE 01 TO WS-JAN-01-DATE(7:2). + + COMPUTE WS-DAY-OF-YEAR = + FUNCTION INTEGER-OF-DATE(WS-DATE-NUMERIC) - + FUNCTION INTEGER-OF-DATE(WS-JAN-01-DATE) + 1. + + *=Display result================================================ + DISPLAY ' ' WS-TEST-NAME ': ' WS-MONTH '/' WS-DAY '/' + WS-YEAR ' (' WS-DAY-NAME ') Day ' WS-DAY-OF-YEAR. + + ADD 1 TO WS-PASSED-TESTS. + + CALCULATE-NTH-WEEKDAY SECTION. + *=Calculate the Nth occurrence of a specific weekday in a month= + *=WS-TARGET-DAY: 1=Sun, 2=Mon, 3=Tue, 4=Wed, 5=Thu, 6=Fri, 7=Sat + *=WS-WEEK-COUNT: Which occurrence (1st, 2nd, 3rd, etc.)========== + + *=Get first day of month======================================== + MOVE 01 TO WS-DAY. + MOVE WS-YEAR TO WS-DATE-NUMERIC(1:4). + MOVE WS-MONTH TO WS-DATE-NUMERIC(5:2). + MOVE WS-DAY TO WS-DATE-NUMERIC(7:2). + + COMPUTE WS-FIRST-DAY-OF-MONTH = + FUNCTION MOD( + FUNCTION INTEGER-OF-DATE(WS-DATE-NUMERIC), 7) + 1. + + *=Calculate which day the Nth occurrence falls on=============== + IF WS-TARGET-DAY >= WS-FIRST-DAY-OF-MONTH + COMPUTE WS-CALCULATED-DAY = + WS-TARGET-DAY - WS-FIRST-DAY-OF-MONTH + 1 + + ((WS-WEEK-COUNT - 1) * 7) + ELSE + COMPUTE WS-CALCULATED-DAY = + WS-TARGET-DAY - WS-FIRST-DAY-OF-MONTH + 8 + + ((WS-WEEK-COUNT - 1) * 7) + END-IF. + + MOVE WS-CALCULATED-DAY TO WS-DAY. + + CALCULATE-LAST-WEEKDAY SECTION. + *=Calculate the last occurrence of a specific weekday in a month + *=WS-TARGET-DAY: 1=Sun, 2=Mon, 3=Tue, 4=Wed, 5=Thu, 6=Fri, 7=Sat + + *=Start with last day of month================================== + EVALUATE WS-MONTH + WHEN 01 MOVE 31 TO WS-DAY + WHEN 02 + IF FUNCTION MOD(WS-YEAR, 4) = 0 + IF FUNCTION MOD(WS-YEAR, 100) = 0 + IF FUNCTION MOD(WS-YEAR, 400) = 0 + MOVE 29 TO WS-DAY + ELSE + MOVE 28 TO WS-DAY + END-IF + ELSE + MOVE 29 TO WS-DAY + END-IF + ELSE + MOVE 28 TO WS-DAY + END-IF + WHEN 03 MOVE 31 TO WS-DAY + WHEN 04 MOVE 30 TO WS-DAY + WHEN 05 MOVE 31 TO WS-DAY + WHEN 06 MOVE 30 TO WS-DAY + WHEN 07 MOVE 31 TO WS-DAY + WHEN 08 MOVE 31 TO WS-DAY + WHEN 09 MOVE 30 TO WS-DAY + WHEN 10 MOVE 31 TO WS-DAY + WHEN 11 MOVE 30 TO WS-DAY + WHEN 12 MOVE 31 TO WS-DAY + END-EVALUATE. + + *=Work backwards to find the last occurrence==================== + PERFORM UNTIL WS-DAY < 1 + MOVE WS-YEAR TO WS-DATE-NUMERIC(1:4) + MOVE WS-MONTH TO WS-DATE-NUMERIC(5:2) + MOVE WS-DAY TO WS-DATE-NUMERIC(7:2) + + COMPUTE WS-FIRST-DAY-OF-MONTH = + FUNCTION MOD( + FUNCTION INTEGER-OF-DATE(WS-DATE-NUMERIC), 7) + 1 + + IF WS-FIRST-DAY-OF-MONTH = WS-TARGET-DAY + EXIT PERFORM + ELSE + SUBTRACT 1 FROM WS-DAY + END-IF + END-PERFORM. + + END PROGRAM TESTHLDY. diff --git a/AS400/COBOL_examples/Holidays/README.md b/AS400/COBOL_examples/Holidays/README.md new file mode 100644 index 0000000..54b1276 --- /dev/null +++ b/AS400/COBOL_examples/Holidays/README.md @@ -0,0 +1,140 @@ +# Holiday Tracking System + +This directory contains AS400 COBOL programs for tracking US Federal Holidays, useful for tax calculations and business planning. + +## Programs + +### HOLYTRK01.CBLLE - Holiday Tracking Program +A comprehensive holiday tracking program that calculates the dates of all major US Federal Holidays for any given year (1600-3000). + +**Features:** +- Calculates fixed-date holidays (New Year's Day, Independence Day, Veterans Day, Christmas) +- Calculates floating holidays based on day-of-week rules: + - Martin Luther King Jr. Day (3rd Monday in January) + - Presidents' Day (3rd Monday in February) + - Memorial Day (Last Monday in May) + - Labor Day (1st Monday in September) + - Columbus Day (2nd Monday in October) + - Thanksgiving Day (4th Thursday in November) +- Displays day of week for each holiday +- Displays day of year (Julian day) for tax calculation purposes +- Interactive interface for checking multiple years + +**Usage:** +```cobol +CALL HOLYTRK01 +``` + +The program will prompt for a year and display all federal holidays for that year with their dates, day of week, and day of year. + +### TESTHLDY.CBLLE - Holiday Test Program +An automated test program that validates the holiday calculations across multiple years (past, present, and future). + +**Features:** +- Tests calculations for years: 2020, 2024, 2025, 2030, and 1776 +- Validates both fixed-date and floating holidays +- Displays comprehensive test results +- Shows pass/fail summary + +**Usage:** +```cobol +CALL TESTHLDY +``` + +The program will automatically run all tests and display results. + +### CANDAY01.CBLLE - Canada Day Calculator +A specialized program for calculating what day of the week Canada Day (July 1st) falls on for any given year. + +**Features:** +- Interactive year input +- Displays day of week for Canada Day +- Provides fun facts about weekend vs. weekday holidays +- Loop capability to check multiple years + +**Usage:** +```cobol +CALL CANDAY01 +``` + +### TESTCDAY.CBLLE - Canada Day Test Program +A test framework for the Canada Day calculator (implementation framework provided). + +## Compilation + +To compile these programs on AS/400: + +1. Upload the source to QCBLLESRC source file: +```cl +FTP ${AS400} +// login +ascii +QUOTE SITE NAMEFMT 0 +PUT HOLYTRK01.CBLLE ${LIB}/QCBLLESRC.HOLYTRK01 (REPLACE +PUT TESTHLDY.CBLLE ${LIB}/QCBLLESRC.TESTHLDY (REPLACE +PUT CANDAY01.CBLLE ${LIB}/QCBLLESRC.CANDAY01 (REPLACE +PUT TESTCDAY.CBLLE ${LIB}/QCBLLESRC.TESTCDAY (REPLACE +``` + +2. Compile using CRTBNDCBL: +```cl +CRTBNDCBL PGM(${LIB}/HOLYTRK01) SRCFILE(${LIB}/QCBLLESRC) SRCMBR(HOLYTRK01) +CRTBNDCBL PGM(${LIB}/TESTHLDY) SRCFILE(${LIB}/QCBLLESRC) SRCMBR(TESTHLDY) +CRTBNDCBL PGM(${LIB}/CANDAY01) SRCFILE(${LIB}/QCBLLESRC) SRCMBR(CANDAY01) +CRTBNDCBL PGM(${LIB}/TESTCDAY) SRCFILE(${LIB}/QCBLLESRC) SRCMBR(TESTCDAY) +``` + +## Holiday Calculation Methods + +### Fixed-Date Holidays +These holidays always occur on the same date each year: +- New Year's Day: January 1 +- Independence Day: July 4 +- Veterans Day: November 11 +- Christmas Day: December 25 + +### Nth Weekday Holidays +These holidays occur on a specific weekday occurrence within a month: +- Martin Luther King Jr. Day: 3rd Monday in January +- Presidents' Day: 3rd Monday in February +- Labor Day: 1st Monday in September +- Columbus Day: 2nd Monday in October +- Thanksgiving Day: 4th Thursday in November + +### Last Weekday Holidays +These holidays occur on the last occurrence of a specific weekday: +- Memorial Day: Last Monday in May + +## Tax Calculation Use Cases + +The day-of-year (Julian day) output is particularly useful for: +- Calculating pro-rated tax amounts +- Determining fiscal year periods +- Planning estimated tax payment deadlines +- Managing payroll processing schedules +- Calculating business days for financial operations + +## Technical Details + +**Date Range:** 1600-3000 (limited by COBOL INTEGER-OF-DATE function) + +**Date Calculations:** +- Uses COBOL intrinsic function `INTEGER-OF-DATE` for accurate date arithmetic +- Accounts for leap years using standard Gregorian calendar rules +- Day of week calculation using modulo 7 arithmetic +- Julian day calculation from January 1st of the year + +**Error Handling:** +- Year range validation +- Input validation +- Graceful error messages + +## Future Enhancements + +Possible additions: +- Add state-specific holidays +- Add religious holidays +- Export to file for batch processing +- Add holiday observance rules (when holiday falls on weekend) +- Add fiscal year calculations +- International holiday support