Teach Yourself COBOL in 21 days, Second Edition

Previous chapterNext chapterContents


- Bonus Day 6 -
Dates and the Year 2000

The approach of the year 2000 (just around the corner now) has produced a great deal of activity regarding dates. The biggest issue is solving the problem of millions of lines of code that use only two digits to represent years. There are also issues involving the rules for leap years and new standards for storing and retrieving date information

Today, you learn about the following parts of the bills-payment system:

More Than You Ever Wanted to Know About Dates

This section covers dating systems and calendars so that you'll understand how computers calculate dates (or miscalculate dates) and the dating techniques used by computers.

I won't make this a history lesson, but suffice it to say that calendars were a source of great consternation in the past (not that we're doing much better these days). They were based on either the lunar month (about 291/2 days), the solar year (about 3651/4 days--note the use of "about" here; it will come back to haunt us), or a combination of both.

There are as many versions of history as there are historians. I would like to say that the following information on the Greco-Roman origins of the calendar is etched-in-bronze irrefutable fact, but the truth is that no one really knows, and calendar historians love to argue about it. For the purposes of this early history, the following should be called the story of the calendar, or perhaps even the legend of the calendar, rather than its history.

The modern Western calendar as we know it has its roots in a Roman calendar that was borrowed from the Greeks. It had 10 months of varying lengths that made up a year of 304 days. The remaining 61 (or 62) days were just left over, lying around for whatever you wanted to do with them. The 10 months were Martius, Aprilis, Maius, Junius, Quintilis, Sextilis, Septembris, Octobris, Novembris, and Decembris. Greedy rulers (gee, Rome had those too?), notably Numa Pompilius, realized that they could collect more taxes if there were more months in a year, so they scooped up the spare days, placed them at the end of the year, and divided them into two more months, Januarius and Februarius. The year started on Martius 1 and ended on the last day of Februarius. In this arrangement, you can see the beginnings of a proto-modern calendar.

The First Julian Calendar

There were still some loose days lying around, and seasons drifted around, appearing in different months in some years. In 46 B.C.E. (Before the Common Era), Julius Caesar grabbed the astronomer Sosigenes and told him to sort things out. Sosigenes devised a year with 12 months of 30 or 31 days each, except for Februarius, which had 29. Every four years, one extra day was added to Februarius to keep the calendar year synchronized with the solar year. In order to align the year with the seasons, Julius declared that the current year should have begun on Januarius 1, and that henceforth each year would begin on that date. The population was also informed that Januarius 1 hadn't occurred when they thought it had, but that it had actually happened more than 20 days earlier. Therefore, the year 46 B.C.E. had many extra days to compensate for all this date-shifting. Romans called it the year of confusion.

In order to honor the calendar reform, and presumably with a fair bit of pressure from Julius himself, the Roman Senate renamed the month Quintilis to Julius (which, of course, is now July).

Does all this sound familiar? You have a 12-month year starting in Januarius; each month has 30 or 31 days, except Februarius, which has 29; and Februarius gains an extra day every four years.

Interestingly, Sosigenes, who actually devised this scheme and was almost right, was never honored in the calendar. Otherwise, Americans might be celebrating the 4th of Sosigeny as Independence Day.

The Calendar According to Augustus

Julius Caesar's successor, Emperor Augustus, who felt that he was every bit as cool as his predecessor, had the month Sextilis renamed Augustus. Officially, the Senate proclaimed this renaming, but it isn't difficult to guess who was lobbying for it.

Unfortunately, the month Julius had 31 days, and the renamed Augustus had only 30. Augustus, upset that his month wasn't as big as Julius's, took a day from Februarius and stuck it onto the end of Augustus, so February ended up having only 28 days most of the time.

The change caused by Augustus was not a very big one, so the calendar was still called the Julian calendar for another 1,500 years.

A final warning. Some serious calendar scholars claim that the whole story so far is learned claptrap and a medieval fabrication by calendar reformers who wanted to create some "history" for their own scheme to regularize the calendar.

Leap Year Drift

Earlier I said that the solar year was about 3651/4 days long. It's actually 11 minutes and 14 seconds shorter than that. You might think that this isn't much to worry about. In the course of a 70-year lifetime, the calendar would drift by only about 13 hours. However, over 1,500 years, the drift was beginning to show. In 1582, the spring equinox, one of those inescapably observable astronomical phenomena, had drifted back to March 11, 10 days earlier than its traditional March 21 date. Something had to be done, and quickly. After all, in another 140 years, the spring equinox would slip to March 10.

The Gregorian Calendar

Pope Gregory XIII turned this problem over to the scholar Aloysius Lilius. He and his brother came up with a solution that involved further fiddling with poor old Februarius. Having an extra day every four years was almost right, but the system could be further tuned with two additional rules.

Here was the original rule:

Here were the additional new rules:

So, for example, 1700, 1800, and 1900 are not leap years, but 2000 is, and 1600 was.

These are the leap year rules that are used in the current calendar.

With all the attention to the year 2000, considerable significance has been attached to the fact that the year 2000 is a leap year. This was caused by a notable series of goofs by more than one software company that applied only the old rule and the first new rule to the year 2000 and determined that 2000 was not a leap year.

So much attention is attached to this issue that you might be asked about it in a job interview. Is the year 2000 a leap year, and why or why not?

Adjusting the Drift

The new rules worked well, but something had to be done about the 10-day drift. The Pope handled this by proclaiming that the day that should have been October 5, 1582 would be October 15, 1582. So the days October 5 through October 14, 1582 don't actually exist in the Gregorian calendar.

Of course, the new calendar didn't roll out overnight. The average man-in-the-street (in those days known as the average peasant-in-ye-muddy-rutted-path) didn't have the benefit of the 9 o'clock news to warn him of the changes. There was also political resistance to the change. It took Great Britain 200 years to get with the program. They went Gregorian in 1752, calling it the New Style calendar, and declared that the day following September 2, 1752 would be September 14, 1752. They also ordered all colonies to adopt the new date conventions. Note that because Great Britain waited 200 years before adopting the Gregorian calendar, it had to drop 11 days, September 3 through 13, one day more than Gregory had to drop in 1582 (October 5 through 14).

Turkey didn't adopt the new calendar until 1927. Since each country adopted the calendar at a different time, calendar adjustments happened at different times in various parts of the world. There are missing days in different periods for each location, depending on when the country in question adopted the calendar and which days were disposed of to adjust for the adoption.

The Gregorian calendar is very accurate in keeping pace with the solar year. It is still about 26 seconds too long, so in a few thousand years, that pesky spring equinox will have drifted off by a day. I guess we will cross that bridge when we come to it.

The Gregorian calendar is not the only calendar. The Islamic calendar is based on a lunar calendar with leap year adjustments and is quite accurate, although the year drifts through a complete cycle every 30 years. On the Hebrew calendar, the current year (1997) is 5757, and their year begins in autumn. There are many more. Because the Gregorian calendar is used for most business computing, it is the calendar that this chapter deals with.

The Other Julian System

In 1582, Joseph Scaliger devised another dating system called the Julian period. He numbered days starting from noon on January 1, 4713 B.C.E. Noon on December 31, 1994 was the beginning of Julian Day 2,449,718.

The starting date for the Julian period was chosen because it was the convergence in recent history of three earlier chronological cycles that were used for determining dates: the 28-year solar cycle, the 19-year lunar cycle, and the 15-year Roman Tax cycle, also called the indiction cycle. Julian period dating is used today in astronomy as a convenient method of dating astronomical events. This has advantages on an international scale because the Gregorian calendar was adopted at different times in different places. June 3, 1602 is not the same day to an Italian astronomer whose country was on the Gregorian calendar and an English astronomer whose country was not. Scaliger named the system after his father, Julius, not after the Julian calendar. This Julian period dating system is frequently called the Julian calendar or Julian Day, which causes some confusion with the Julius Caesar version.

Julian Dates

Just to throw another Julian into the pot, the computer industry has developed a date format containing five or seven digits, composed of a two- or four-digit year and a three-digit day of the year. This format does not have a month in it but simply counts the days from the beginning of the year with January 1 being day 1. Thus, January 1, 1997 is 97001 or 1997001, and February 2, 1998 becomes 1998033 or 98033. This date format is used in a lot of military software. This format should be called Ordinal Day of the Year or Ordinal Year Day Format, but somewhere along the line the name Julian was applied, and it stuck.

Gregorian Versus Julian Formats

In the computer business, two naming conventions have arisen for two date formats: Julian format, as already described, and Gregorian format. Gregorian dates are those stored with a year (2 or 4 digit), a month, and a day (without regard to the order of these numbers) as 970213 or 02131997.

Both Julian and Gregorian formats use the underlying Gregorian calendar, but the term Julian date has been in use long enough now that it will persist. Even IBM uses the terms Julian date and Julian format to refer to the ordinal day of the year format of a two- or four-digit year followed by a three-digit day of the year.

A Final Note on the Julians

With so much attention on the year 2000, a new breed of programmer has appeared--the arcane date trivia buff. These folks are characterized by a tendency to correct you vehemently whenever you refer to a date as a Julian date when it is in Julian format. They will trot out either the Julian calendar (Caesar's) or the Julian period dating system (Scaliger's) and proceed to beat you over the head with it to illustrate what a dolt you are for not knowing that the year-year-day-day-day format is actually in the Gregorian calendar but uses the ordinal day and year format.

These folks usually also know all about Scaliger's Julian period or Julian Day dates and incorrectly call it the Julian calendar and then criticize you for defining the Julian calendar as the calendar developed at Julius Caesar's order in 46 B.C.E., or vice versa.

A third piece of information that these date buffs love thrusting down your throat is the fact that the year 2000 is not the beginning of the 21st century; it is the last year of the 19th century. Because there is no year 0, the 1st century was years 1 through 100, the 2nd century was years 101 through 200, and so on up to the 20th century, which is the years 1901 through 2000. 2001 is the first year of the 21st century. This has nothing to do with computer date problems, but when some people get going, they just can't stop. It does mean that we will have two great New Year's celebrations back to back: the first to incorrectly celebrate the end of the 20th century on December 31, 1999, and the other to correctly celebrate it on December 31, 2000.

Don't be too hard on these people just because you now know the correct answers. Just smile and refer them to a good encyclopedia.

Lilian Dates

The Lilian dating system was named for Aloysius Lilius, one of the two brothers who were instrumental in developing the Gregorian calendar. The Lilian dating system is based on counting the number of days since October 14, 1582. The Gregorian calendar was deployed by papal decree on October 15, 1582, or Lilian day 1.

This system of creating dates by counting days from a specified date in the past has been used in various calendars and dating systems, including the Julian period system devised by Joseph Scaliger. The American National Standards Institute (ANSI) adopted a system of counting days starting from December 31, 1600 as Day 0. Thus, January 1, 1601 is ANSI Day 1. This format is referred to as the ANSI or ISO (International Standards Organization) date format.

The Lilian and ANSI date formats are two examples of a style of dating usually called integer-day dating systems or day-as-integer dates.

The Lilian and ANSI day dating systems use large numbers to store the number of days since a particular start date. For example, January 1, 1998 will be ANSI day 145,002.

Dating Systems Used on Computers

What does all this have to do with computers? You will commonly find the following seven date types on computers:

If you work on computers that store astronomical data, you might run into Julian period dates, in which a date is stored as a number of days from noon on January 1, 4713 B.C.E. Julian period dates are beyond the scope of this chapter.

Even less likely and also beyond the scope of this chapter might be software that tracks archaeological finds or historical documents on the Julian (Caesar's) calendar, the Mayan calendar, or any other possible dating system based on the culture associated with the artifact.

Intrinsic Functions for Dates

Several intrinsic functions are designed to handle dates. Table B6.1 lists each function, its arguments, and its return values.

Table B6.1. Date functions.

Function Name Content of Arguments Data Type of Arguments Content of Returned Value Data Type of Returned Value
CURRENT-DATE None None Current date, time, and GMT difference1 Alphanumeric
DATE-OF-INTEGER ANSI date2 Integer Gregorian date3 Integer
DAY-OF-INTEGER ANSI date2 Integer Julian date4 Integer
INTEGER-OF-DATE Gregorian date3 Integer ANSI date2 Integer
INTEGER-OF-DAY Julian date4 Integer ANSI date2 Integer

An integer is a whole number.

1Current date, time, and Greenwich Mean Time (GMT) difference. A date and time in the format CCYYMMDDHHMMSSDD followed by a sign and four digits of difference from GMT in HHMM format. In the format CC = hundreds of years, YY = years, MM = month 1-12, DD = day 1-31, HH = hour 0-23, MM = minutes 0-59, SS = seconds 0-59 and DD = hundredths of a second 0-99. When it is 7:55 pm in Greenwich, it is also 7:55 pm in Dublin, Ireland, and the GMT difference will appear as +0000. In Moscow it will be 10:55 pm, and the GMT difference will be +0300. Los Angeles, California is eight hours earlier than GMT. The time there will be 11:55 am, and the GMT difference will be -0800. All of these numbers ignore any shifts that occur for Daylight savings time.

2The number of days since December 31, 1600.

3A date in the format YYYYMMDD.

4A date in the format YYYYDDD. Bonus Day 5, "Intrinsic Functions and the Year 2000," covered the CURRENT-DATE function, so let's look at some of the others.

Day of the Week

One of the reasons that the ANSI committee chose January 1, 1601 to be Day 1 of the ANSI date-recording technique is that January 1, 1601 also happens to be a Monday. This makes it possible to combine the REM function with the INTEGER-OF-DATE function to calculate the day of the week for dates equal to or greater than January 1, 1601, which is day 1 of the ANSI dating system.

Table B6.2 shows you how the day of the week is calculated using the ANSI date in days, dividing it by 7, and using the remainder to determine the actual day of the week for that date. It lists a date starting from January 1, 1601, the ANSI day, which is the remainder of dividing the ANSI day by 7 and the day of the week for the date. The pattern shows a remainder of 1 for Mondays, 2 for Tuesdays, and so on through to Sunday, which returns a remainder of zero. This pattern repeats for successive dates all the way to the present. A remainder of 0 represents a Sunday, 1 is a Monday, and so on through Friday, which is 6. Hark back to your early elementary school long division classes when looking at the table, and you will remember that 1 divided by 7 produces a result of 0 and a remainder of 1, 2 divided by 7 also produces a result of 0 but a remainder of 2, and so on.

To determine the day of the week for any date from January 1, 1601, you need to convert the date to ANSI days using the INTEGER-OF-DATE function and find the remainder of dividing that number by 7 using the REM function. The INTEGER-OF-DATE function will not work correctly for dates prior to January 1, 1601.

Table B6.2. Day-of-the-week calculations.

Date ANSI Date REM (Remainder of ANSI Date Divided by 7) Day of the Week
Jan 1, 1601 1 1 Monday
Jan 2, 1601 2 2 Tuesday
Jan 3, 1601 3 3 Wednesday
Jan 4, 1601 4 4 Thursday
Jan 5, 1601 5 5 Friday
Jan 6, 1601 6 6 Saturday
Jan 7, 1601 7 0 Sunday
Jan 8, 1601 8 1 Monday
Jan 9, 1601 9 2 Tuesday
Jan 10, 1601 10 3 Wednesday
Jan 11, 1601 11 4 Thursday
Jan 12, 1601 12 5 Friday
Jan 13, 1601 13 6 Saturday
Jan 14, 1601 14 0 Sunday
Jan 15, 1601 15 1 Monday

Listing B6.1, DOW.CBL, uses the REM and the INTEGER-OF-DATE functions to calculate the day of the week of the current system date and a date entered by the user. It does this using two different styles.

TYPE: Listing B6.1. DOW.CBL.

000100 IDENTIFICATION DIVISION.
000200 PROGRAM-ID. DOW.
000300 AUTHOR. MO BUDLONG.
000400 INSTALLATION.
000500 DATE-WRITTEN. 09/07/96.
000600 DATE-COMPILED.
000700 SECURITY. NONE
000800 ENVIRONMENT DIVISION.
000900 INPUT-OUTPUT SECTION.
001000 FILE-CONTROL.
001100 DATA DIVISION.
001200 FILE SECTION.
001300 WORKING-STORAGE SECTION.
001400
001500 01  CD-DATE.
001600     05  CD-YYYYMMDD          PIC 9(8).
001700     05  FILLER               PIC X(13).
001800 01  THE-DATE                 PIC 9(8).
001900 01  ANSI-DATE                PIC 9(6).
002000 01  THE-DOW                  PIC 9.
002100
002200 01  DAYS-OF-WEEK.
002300     05  FILLER               PIC X(9) VALUE "SUNDAY".
002400     05  FILLER               PIC X(9) VALUE "MONDAY".
002500     05  FILLER               PIC X(9) VALUE "TUESDAY".
002600     05  FILLER               PIC X(9) VALUE "WEDNESDAY".
002700     05  FILLER               PIC X(9) VALUE "THURSDAY".
002800     05  FILLER               PIC X(9) VALUE "FRIDAY".
002900     05  FILLER               PIC X(9) VALUE "SATURDAY".
003000 01  FILLER REDEFINES DAYS-OF-WEEK.
003100     05  THE-DAY              PIC X(9) OCCURS 7 TIMES.
003200
003300 01  DOW-SUB                  PIC 9.
003400
003500 01  DUMMY     PIC X.
003600
003700 PROCEDURE DIVISION.
003800 MAIN-LOGIC SECTION.
003900 PROGRAM-BEGIN.
004000
004100     PERFORM OPENING-PROCEDURE.
004200     PERFORM MAIN-PROCESS.
004300     PERFORM CLOSING-PROCEDURE.
004400
004500 EXIT-PROGRAM.
004600     EXIT PROGRAM.
004700 STOP-RUN.
004800     STOP RUN.
004900
005000
005100 THE-OTHER SECTION.
005200
005300 OPENING-PROCEDURE.
005400 CLOSING-PROCEDURE.
005500 MAIN-PROCESS.
005600     MOVE 1 TO THE-DATE.
005700     PERFORM ENTER-PARAMETERS.
005800     PERFORM TEST-DOW UNTIL
005900         THE-DATE = 0.
006000
006100 ENTER-PARAMETERS.
006200     DISPLAY "ENTER A DATE IN YYYYMMDD FORMAT (0 TO QUIT)".
006300     ACCEPT THE-DATE.
006400
006500 TEST-DOW.
006600     MOVE FUNCTION CURRENT-DATE TO CD-DATE.
006700
006800     COMPUTE ANSI-DATE = FUNCTION INTEGER-OF-DATE(CD-YYYYMMDD).
006900     COMPUTE THE-DOW = FUNCTION REM(ANSI-DATE,7).
007000     COMPUTE DOW-SUB = THE-DOW + 1.
007100
007200     DISPLAY "TODAY IS " CD-YYYYMMDD " A "
007300         THE-DAY(DOW-SUB).
007400
007500     COMPUTE DOW-SUB = FUNCTION REM(
007600         FUNCTION INTEGER-OF-DATE(THE-DATE), 7) + 1.
007700
007800     DISPLAY THE-DATE " IS A "
007900         THE-DAY(DOW-SUB).
008000
008100     DISPLAY "PRESS ENTER TO CONTINUE . . . "
008200     ACCEPT DUMMY.
008300
008400     PERFORM ENTER-PARAMETERS.
008500

OUTPUT:

C:\pcobol\DATE8\intrnsic>PCOBRUN DOW
Personal COBOL version 2.0 from Micro Focus
PCOBRUN V2.0.02  Copyright (C) 1983-1993 Micro Focus Ltd.
ENTER A DATE IN YYYYMMDD FORMAT (0 TO QUIT)
16010101
TODAY IS 19970112 A SUNDAY
16010101 IS A MONDAY
PRESS ENTER TO CONTINUE . . .
ENTER A DATE IN YYYYMMDD FORMAT (0 TO QUIT)
19970113
TODAY IS 19970112 A SUNDAY
19970113 IS A MONDAY
PRESS ENTER TO CONTINUE . . .
ENTER A DATE IN YYYYMMDD FORMAT (0 TO QUIT)
19480304
TODAY IS 19970112 A SUNDAY
19480304 IS A THURSDAY
PRESS ENTER TO CONTINUE . . .
ENTER A DATE IN YYYYMMDD FORMAT (0 TO QUIT) 

ANALYSIS: In lines 006600 through 007400, the CURRENT-DATE is extracted and then converted to an ANSI date. The remainder division is performed on the ANSI date, and the result is placed in DOW. DOW is used to create a subscript DOW-SUB into the DAYS-OF-WEEK table, and the result is displayed.

The second version starting on line 007500 uses a feature of intrinsic functions. The result of an intrinsic function can be used directly as an argument to another intrinsic function. The second version computes the value of DOW-SUB in one statement on lines 007500 and 007600. Let's analyze this statement and see how it works while the computer executes the statement. First, it helps to scrunch everything onto one line:

COMPUTE DOW-SUB = FUNCTION REM( FUNCTION INTEGER-OF-DATE(THE-DATE), 7) + 1.

For this example, I will assume that the entered date is 16010108 (January 8, 1601), a Monday. Functions, just like arithmetic statements, are evaluated from the inside out. The first thing the computer does is replace the THE-DATE for the INTEGER-OF-DATE function with the actual value that was entered, 16010108:

COMPUTE DOW-SUB = FUNCTION REM( FUNCTION INTEGER-OF-DATE(16010108), 7) + 1.

The inner function, FUNCTION INTEGER-OF-DATE(16010108), is resolved to ANSI Day 8, and the statement becomes

COMPUTE DOW-SUB = FUNCTION REM(8, 7) + 1.

Now the REM(8, 7) function is performed and resolves to 1:

COMPUTE DOW-SUB = 1 + 1.

Finally, the value 2 is assigned to DOW-SUB, which points to the value "MONDAY" in the DAYS-OF-WEEK table, which is what we were after.

Adding Days to a Date

It's possible to use INTEGER-OF-DATE and the inverse function DATE-OF-INTEGER to calculate a new date when a number of days are added to an existing date. Listing B6.2, DADD.CBL, illustrates one method of doing this by adding a positive or negative number to the current date.

TYPE: Listing B6.2. DADD.CBL: Adds days to a date.

000100 IDENTIFICATION DIVISION.
000200 PROGRAM-ID. DADD.
000300 AUTHOR. MO BUDLONG.
000400 INSTALLATION.
000500 DATE-WRITTEN. 09/07/96.
000600 DATE-COMPILED.
000700 SECURITY. NONE
000800 ENVIRONMENT DIVISION.
000900 INPUT-OUTPUT SECTION.
001000 FILE-CONTROL.
001100 DATA DIVISION.
001200 FILE SECTION.
001300 WORKING-STORAGE SECTION.
001400
001500 01  CD-DATE.
001600     05  CD-YYYYMMDD          PIC 9(8).
001700     05  FILLER               PIC X(13).
001800 01  NEW-DATE                 PIC 9(8).
001900 01  DAYS-TO-ADD              PIC S9(5).
002000 01  FORMAT-DAYS-TO-ADD       PIC ZZZZ9-.
002100
002200 01  DUMMY     PIC X.
002300
002400 PROCEDURE DIVISION.
002500 MAIN-LOGIC SECTION.
002600 PROGRAM-BEGIN.
002700
002800     PERFORM OPENING-PROCEDURE.
002900     PERFORM MAIN-PROCESS.
003000     PERFORM CLOSING-PROCEDURE.
003100
003200 EXIT-PROGRAM.
003300     EXIT PROGRAM.
003400 STOP-RUN.
003500     STOP RUN.
003600
003700
003800 THE-OTHER SECTION.
003900
004000 OPENING-PROCEDURE.
004100 CLOSING-PROCEDURE.
004200 MAIN-PROCESS.
004300     MOVE 1 TO DAYS-TO-ADD.
004400     PERFORM ENTER-PARAMETERS.
004500     PERFORM TEST-DADD UNTIL
004600         DAYS-TO-ADD = 0.
004700
004800 ENTER-PARAMETERS.
004900     DISPLAY "ENTER NUMBER-OF-DAYS TO ADD (0 TO QUIT)".
005000     ACCEPT DAYS-TO-ADD.
005100     MOVE DAYS-TO-ADD TO FORMAT-DAYS-TO-ADD.
005200
005300 TEST-DADD.
005400     MOVE FUNCTION CURRENT-DATE TO CD-DATE.
005500
005600     COMPUTE NEW-DATE =
005700         FUNCTION DATE-OF-INTEGER(
005800            FUNCTION INTEGER-OF-DATE(CD-YYYYMMDD)
005900          + DAYS-TO-ADD).
006000
006100     DISPLAY "CURRENT DATE " CD-YYYYMMDD
006200             " + "  FORMAT-DAYS-TO-ADD
006300             " WILL BE " NEW-DATE.
006400
006500     PERFORM ENTER-PARAMETERS.
006600

OUTPUT:

Accepted - CONFIRM
ENTER NUMBER-OF-DAYS TO ADD (0 TO QUIT)
15
CURRENT DATE 19970112 +    15  WILL BE 19970127
ENTER NUMBER-OF-DAYS TO ADD (0 TO QUIT)
-1
CURRENT DATE 19970112 +     1- WILL BE 19970111
ENTER NUMBER-OF-DAYS TO ADD (0 TO QUIT)
-30
CURRENT DATE 19970112 +    30- WILL BE 19961213
ENTER NUMBER-OF-DAYS TO ADD (0 TO QUIT)
-500
CURRENT DATE 19970112 +   500- WILL BE 19950831
ENTER NUMBER-OF-DAYS TO ADD (0 TO QUIT)
-365
CURRENT DATE 19970112 +   365- WILL BE 19960113
ENTER NUMBER-OF-DAYS TO ADD (0 TO QUIT)
-366
CURRENT DATE 19970112 +   366- WILL BE 19960112
ENTER NUMBER-OF-DAYS TO ADD (0 TO QUIT)
+365
CURRENT DATE 19970112 +   365  WILL BE 19980112
ENTER NUMBER-OF-DAYS TO ADD (0 TO QUIT) 

ANALYSIS: The technique of using the return value of a function as an argument to another function is used in lines 005600 through 005900. In the following example, the line is too wide for this book's margins, so it is broken into two lines. The statement starts out as follows:

COMPUTE NEW-DATE = FUNCTION DATE-OF-INTEGER (
ÂFUNCTION INTEGER-OF-DATE(CD-YYYYMMDD) + DAYS-TO-ADD).

Assuming that the current date is 19970112 and that the user entered -30 as the days offset, the function resolves in stages. Again, the following line is split across two lines. First, the value of the current date is plugged into the INTEGER-OF-DATE function:

COMPUTE NEW-DATE = FUNCTION DATE-OF-INTEGER (
ÂFUNCTION INTEGER-OF-DATE(19970112) + DAYS-TO-ADD).

The ANSI days are calculated by calling INTEGER-OF-DATE and replacing the function call:

COMPUTE NEW-DATE = FUNCTION DATE-OF-INTEGER(144,648 + DAYS-TO-ADD).

DAYS-TO-ADD is plugged into the formula, and the arithmetic is done:

COMPUTE NEW-DATE = FUNCTION DATE-OF-INTEGER(144,648 + (-30)).
COMPUTE NEW-DATE = FUNCTION DATE-OF-INTEGER(144,618).

Finally, the DATE-OF-INTEGER function is called with this value and returns 19961231, which is assigned to NEW-DATE:

COMPUTE NEW-DATE = 19961231.

What Is the Year 2000 Problem?

Now that you have seen what can be done with intrinsic functions operating on dates, it's time to look at the year 2000 problem. COBOL programs, as well as other software, including even the software that displays the date and time on your IBM-compatible PC, use a six-digit date. The date, in YYMMDD or MMDDYY format, and the accompanying code assume 19 for the first part of the year and store, for example, November 12, 1997 as 971112 or 111297. January 1, 2000 would become 000101. This will mess up a lot of sorting logic and other parts of the program.

For many, the problem is upon them already. Financial institutions are currently dealing with the maturation date of five-year CDs, for example. My insurance company has calculated my life insurance premium based on an actuarial table that estimates my death in a four-digit year that begins with a 20, not an assumed 19. At least I hope so!

For other companies, the problem will have to be solved by the beginning of 1999. This will allow purchase orders, due dates, delivery dates, and other future-based transactions to be processed correctly.

Some people erroneously believe that the problem has already been solved. I recently attended a demonstration of a payroll package that displayed dates with a four-digit year. After I used the package and tried a few options, something struck me as odd about the dates. I ran a few quick tests. I wasn't allowed to see the source code, but I hypothesized that the logic read something like this:

IF YY > 20
    PERFORM FORMAT-AS-1900
ELSE
    PERFORM FORMAT-AS-2000

The date hadn't been converted to YYYY format. Instead, a simple hack had been put in to display years ending in 21 and greater as 1921, 1922, and so on, and years ending in 00 to 20 as 2000, 2001, and so on.

The logic didn't hold up under a few simple sorts. Reports showed the year 2001 as occurring prior to the year 1921. The package cost almost $60,000, and the sales representative was devastated when I pointed out the nature of the internal coding error. I wrote it up in detail so that their technical people could see the problem. Many months of coding will be required to correct the mistake and all the other date problems that presumably exist in the system. By then I will have chosen another package in which the problem has truly been solved, and the sale will have been lost. This is one example of the problem.

In systems that use six-digit YYMMDD formatted dates or five-digit YYDDD Julian Dates, routines already exist to handle standard business calculations such as calculating the day of the week using a five- or six-digit date or adding days to an existing date and coming up with the new date. To move these routines to the larger date format needed to accommodate the year 2000, all of these routines would have to be rewritten to accommodate the four-digit year format. Additionally, the DATE used in ACCEPT statements such as ACCEPT SYSTEM-DATE FROM DATE is a six-digit date, and extracting the system date in an eight-digit format would require complex coding and calling techniques. Fortunately, intrinsic functions make this task much easier.

Other difficult date problems are sitting on systems based on coding practices that have developed. At one time, it was common to use a date of 990909 to indicate some special condition for a date. It was frequently used to mean "forever." An archive file or tape might be given an expiration date of 990909 to indicate that it was a permanent archive, never to be deleted. Of course, in a couple of years, "forever" will actually arrive, and unless the date is fixed, archives could be inadvertently deleted. Other popular "forever" dates are 990101 and 991231.

Solutions for Year 2000 Problems

The year 2000 problem goes far beyond business date routines. Intrinsic functions take care of many of the existing business routines, but they don't address the real core of the problem. Dates that are stored with a two-digit year are time bombs waiting to explode the first time someone tries to enter or process transactions with a date of January 1, 2000 or greater. This problem could easily surface on a large scale in early 1999 when users try to enter future receiving dates for inventory on order.

Incorrect date handling is already a problem in some credit card machines. Cards with an expiration date in the year 2000 or beyond are being refused. Credit card companies that have completed their year 2000 programming are finding their cards are rejected by credit card machines because the machine itself extracts only the last two digits of the year--00, 01, 02, or whatever--and assumes that the card is expired. The machine doesn't even try to connect to the central clearinghouse to clear the transaction.

As we get closer to 2000, the problem will become more and more severe. All data that is stored with a two-digit date must be modified to allow for these upcoming dates--either by modifying the dates in the file and the programs that read the file, or by modifying the way programs interpret the data in the file. Either way, millions of lines of code will need to be modified to handle this situation over the next three years.

There are two basic methods for solving the year 2000 problem:

Additional Information

The year 2000 situation is rapidly changing, and it is impossible to keep up-to-date on everything. The intent of this chapter isn't to help you sweep into a company to fix all its date problems, but to help you become an employable resource who can be used as part of a date-handling team. For further information on the year 2000 problem, I recommend reading the following:

Summary

The year 2000 problem will demand huge programming resources. This will include extremely skilled analysts who can sort out the problem and determine how to approach it, as well as many people who can code and test the solutions that the analyst comes up with. In this lesson, you learned the following:

Q&A

Q Where are Lilian Dates used?

A IBM has adopted Lilian dates in many instances as an alternative to ANSI dates. Some of their machines and systems provide routines that perform the same functions as INTEGER-FROM-DATE and DATE-FROM-INTEGER but use the Lilian date as the base date. The main difference in using Lilian dates is that Lilian Day 1--October 15, 1582--was a Friday, while ANSI Day 1--January 1, 1601--was a Monday. This changes the behavior of any day-of-the-week logic:

    Date Lilian Date REM (Lilian Date Divided by 7) Day of the Week
    Oct 15, 1582 1 1 Friday
    Oct 16, 1582 2 2 Saturday
    Oct 17, 1582 3 3 Sunday
    Oct 18, 1582 4 4 Monday
    Oct 19, 1582 5 5 Tuesday
    Oct 20, 1582 6 6 Wednesday
    Oct 21, 1582 7 0 Thursday
    Oct 22, 1582 1 1 Friday
    Oct 23, 1582 2 2 Saturday
    Oct 24, 1582 3 3 Sunday
    Oct 25, 1582 4 4 Monday
    Oct 26, 1582 5 5 Tuesday
    Oct 27, 1582 6 6 Wednesday
    Oct 28, 1582 7 0 Thursday

Q Is there a fix or simple software solution for year 2000 problems?

A So far there isn't, and it seems very unlikely that there will be. Several expensive software packages on the market analyze the problem by searching through source code for DATE, YMD, YYMMDD, and other similar words. These packages perform a variety of source-code analysis tricks to point you toward the problem, but so far, the work of fixing and testing is a manual task. An automated solution is unlikely.

One example from a school is a file containing a data item:

05  THE-SEMESTER            PICTURE 9(3).
This is actually a two-digit year and a one-digit month (3, 6, or 9) for the beginning month of the semester, a YYM format. No analysis program would ever pick this up as a date problem, because nothing in the data item THE-SEMESTER or PICTURE 9(3) would cause an automated computer program to think this might be a date.

Q Can ANSI days be used to calculate days and dates prior to January 1, 1601?

A Some systems might allow it, but Microfocus Personal COBOL does not. The ANSI days date format is defined as "days since December 31, 1600," which implies only going forward in time from that date.

Workshop

Quiz

1. How are the Lilian days date format and the ANSI days date format similar?

2. What does the following call to REM return as a value that is stored in RESULT?
COMPUTE RESULT = REM(15, 4).
3. What are the rules for determining if a year is a leap year?

4. Which of the following are leap years?

1600 1700 1901 1955 1996 2000

Exercise

Develop a program that will let you enter two dates and will then tell you the number-of-days difference between the two.

Hint: If you convert the two dates to ANSI dates using INTEGER-OF-DATE, the two numbers can be subtracted from one another.


Previous chapterNext chapterContents


© Copyright, Macmillan Computer Publishing. All rights reserved.