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:
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.
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.
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.
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.
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?
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.
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.
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.
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.
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.
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.
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.
Several intrinsic functions are designed to handle dates. Table B6.1 lists each function, its arguments, and its return values.
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.
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.
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.
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.
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.
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.
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.
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:
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:
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:
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 |
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).
COMPUTE RESULT = REM(15, 4).
Hint: If you convert the two dates to ANSI dates using INTEGER-OF-DATE, the two numbers can be subtracted from one another.
© Copyright, Macmillan Computer Publishing. All rights reserved.