Skip to content

Zaneham/cobol-dateutil

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cobol-dateutil

Date arithmetic for COBOL because every mainframe shop on earth has reinvented this at least twice and at least one of those implementations gets leap years wrong.

Two copybooks. Twenty-three tests. No dependencies. Just COPY it into your program and stop arguing about whether 1900 was a leap year (it wasn't, but Excel thinks it was, and that's a story for another day).

What You Get

Fourteen date operations covering everything from basic day-of-week calculation through to ISO 8601 week numbers and the day count conventions that bond traders argue about at dinner parties. All of it works in integer arithmetic with COMP-3 fields because floating point has no place near a date calculation and certainly no place near your money.

The Julian Day Number algorithm comes from Fliegel and Van Flandern (1968) for the forward direction and Richards (2013) for the reverse, which is the same lineage NASA used for trajectory calculations. Your batch job probably doesn't need that level of rigour but it certainly doesn't hurt.

Quick Start

Put the copybooks somewhere your compiler can find them and then do this:

       WORKING-STORAGE SECTION.
       COPY DATEUTIL.

       PROCEDURE DIVISION.
           MOVE 2026 TO WS-DT-YYYY
           MOVE 03   TO WS-DT-MM
           MOVE 25   TO WS-DT-DD
           PERFORM DU-DAY-OF-WEEK
           DISPLAY "Day of week: " WS-DAY-OF-WEEK

           MOVE 5 TO WS-DAY-COUNT
           PERFORM DU-ADD-BUSINESS-DAYS
           DISPLAY "5 biz days later: "
               WS-DTR-YYYY "/" WS-DTR-MM "/" WS-DTR-DD
           STOP RUN.

       COPY DATECALC.

The COPY DATEUTIL goes in your WORKING-STORAGE SECTION and brings in all the data fields. The COPY DATECALC goes after your own paragraphs in the PROCEDURE DIVISION and brings in all the calculation paragraphs. Set the input fields, PERFORM the paragraph, read the output fields. If you have written COBOL before this will feel completely natural and if you haven't then I admire your bravery.

Available Operations

The Basics

Paragraph Input Output What It Does
DU-CHECK-LEAP-YEAR WS-DT-YYYY WS-IS-LEAP-YEAR Checks all four leap year rules including the century exception that most people forget about
DU-VALIDATE-DATE WS-DT-YYYY/MM/DD WS-IS-VALID-DATE Validates month bounds, day bounds, and leap February correctly
DU-DAY-OF-WEEK WS-DT-YYYY/MM/DD WS-DAY-OF-WEEK Returns 1 for Monday through 7 for Sunday via Julian Day Number
DU-DAY-OF-YEAR WS-DT-YYYY/MM/DD WS-DAY-OF-YEAR Returns 1 through 366 because sometimes you just need to know

Business Day Logic

Paragraph Input Output What It Does
DU-IS-BUSINESS-DAY WS-DT-YYYY/MM/DD WS-IS-BUSINESS-DAY Monday through Friday returns yes, weekends return no. Does not check public holidays because that is your country's problem and not a copybook's
DU-ADD-BUSINESS-DAYS WS-DT-YYYY/MM/DD, WS-DAY-COUNT WS-DATE-RESULT Adds N business days, skipping weekends. Handles negative values for going backwards
DU-BUSINESS-DAYS-CT WS-DATE-WORK, WS-DATE-WORK-2 WS-BUSINESS-DAYS-CT Counts the Monday through Friday days between two dates

Date Arithmetic

Paragraph Input Output What It Does
DU-DAYS-BETWEEN WS-DATE-WORK, WS-DATE-WORK-2 WS-DAYS-BETWEEN Signed difference in days between two dates, negative if the first is later
DU-ADD-DAYS WS-DT-YYYY/MM/DD, WS-DAY-COUNT WS-DATE-RESULT Adds or subtracts calendar days, correctly rolling across month and year boundaries

Finance

Paragraph Input Output What It Does
DU-DAY-COUNT-FRAC WS-DATE-WORK, WS-DATE-WORK-2, WS-DAY-COUNT WS-DAY-COUNT-FRAC Year fraction using your choice of day count convention
DU-LAST-DAY-OF-MONTH WS-DT-YYYY, WS-DT-MM WS-LAST-DAY-OF-MONTH Returns 28, 29, 30, or 31 as appropriate
DU-IS-END-OF-MONTH WS-DT-YYYY/MM/DD WS-IS-END-OF-MONTH Whether the given date is the last day of its month
DU-QUARTER WS-DT-YYYY, WS-DT-MM WS-QUARTER, WS-QUARTER-START, WS-QUARTER-END Fiscal quarter number plus the start and end dates of that quarter
DU-ISO-WEEK WS-DT-YYYY/MM/DD WS-ISO-WEEK, WS-ISO-YEAR ISO 8601 week number and year, which is the standard that occasionally puts January 1st in the previous year's week 53 just to keep things interesting

Day Count Conventions

Set WS-DAY-COUNT before calling DU-DAY-COUNT-FRAC:

Code Convention Denominator Used By
1 ACT/ACT 365 or 366 US Treasury bonds
2 ACT/360 360 Money markets, LIBOR
3 ACT/365 365 (fixed) UK gilts, Japanese bonds
4 30/360 360 US corporate bonds, mortgages
5 30/365 365 Rare but it exists and someone will need it

Building and Testing

The test suite runs on GnuCOBOL and should run on any COBOL-85 compliant compiler including IBM Enterprise COBOL on z/OS and Micro Focus. On GnuCOBOL:

cobc -x -I src -o testdate test/TESTDATE.cbl
./testdate

You should see 23 tests pass and 0 tests fail. If you see anything else then something has gone wrong and I would like to hear about it.

Files

src/
  DATEUTIL.cpy    Data definitions (WORKING-STORAGE)
  DATECALC.cpy    Calculation paragraphs (PROCEDURE DIVISION)
test/
  TESTDATE.cbl    23-test verification suite

Compatibility

Tested on GnuCOBOL 3.x. The copybooks use COBOL-85 syntax with FUNCTION intrinsics (MOD, INTEGER) which are supported by every modern COBOL compiler. The only thing that might trip you up is if your compiler doesn't support FUNCTION MOD, in which case you have a compiler from before 1985 and honestly that's impressive in its own right.

Should work on z/OS with IBM Enterprise COBOL, z390, Micro Focus, and anything else that implements the COBOL-85 standard. If you run into compatibility issues please open an issue and tell me what compiler you're using so I can add a workaround.

Why This Exists

I got tired of seeing the same date arithmetic bugs in every mainframe codebase I touched. February 29th in non-leap years being accepted as valid. Day-of-week calculations that are off by one because someone used the wrong flavour of Zeller's congruence. Business day logic that counts Saturday as a working day in some obscure code path that only triggers on the last day of the quarter during a leap year.

The Mesopotamians managed a calendar with twelve months of thirty days each five thousand years ago and they didn't even have COMP-3 fields. We can do better than this.

License

Apache 2.0.

About

Date arithmetic for COBOL. Business days, day count conventions, ISO weeks. Two copybooks, 23 tests.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages