sams_teach_yourself_cobol_in_24_hours_-_hour_21_date_manipulation

Sams Teach Yourself COBOL in 24 Hours - Hour 21 Date Manipulation

Return to Teach Yourself COBOL in 24 Hours, COBOL bibliography, COBOL, COBOL DevOps, Awesome COBOL, Awesome IBM Mainframe, IBM Mainframe development, IBM Mainframe bibliography, Fortran

“ (TYCb24H 1998)

Part IV

Miscellaneous Functions

Hour

21 Date Manipulation

22 Other Intrinsic Functions

Hour 21 Date Manipulation

An integral part to most business processes is date manipulation. Dates are important to business for a number of reasons. Virtually everything related to business is tied in some way to a date. From birth dates to expiration dates, dates affect business. Transaction dates track when transactions were created and applied. Payment due dates track when a payment is due or past due. Birth dates are used to determine age. Accounting systems use dates for reporting income and expense. In this hour, concepts relating to date manipulation are covered. The topics include

• Calendar history and the year 2000 problem

• Determining the current system date

• The Current-Date Intrinsic Function

• Finding the number of days between dates

• Determining the day of the week

• Date validation

• Converting to Greenwich mean time

• Calculating the date of Easter

Modern COBOL (since 1989) provides a wealth of Functions for working with and manipulating dates. Before 1989 the only way to determine the system date was to use the Accept verb with the From Date and Day clauses. This technique returned only a two-digit date. In 1989 the 1985 COBOL standard was revised to include a new set of features called Intrinsic Functions. Among these Functions were several relating to date manipulation. These provided several methods to help solve the problem related to dates and the year 2000.

The infamous year 2000 problem stems from the fact that most computer programs use only two digits to represent the year. With the year 2000, this two-digit year is 00. This representation causes problems when compared to previous years, for example 99. The logic of programs is affected because this comparison should show that 2000 is greater than 1999, but 00 compares to be less than 99. The program does not perform correctly in this case.

The 1989 extension to the COBOL standard provided a solution to the problem of retrieving the full 4-digit year from the system. Although every program must be checked and changed, the language provides the necessary tools to accomplish the task.

Determining the Current System Date One function that many programs require is the capability to determine today’s date. COBOL uses three different, but related, clauses with the Accept verb to obtain the date.

The first method returns the Gregorian date, which is the date as you are used to seeing it. Pope Gregory XIII instituted the Gregorian calendar in 1582, and it was slowly adopted by the entire world. This calendar is a modification of the Julian calendar that had become incorrect over time. The date correction involved with the change to the Gregorian calendar did not interrupt the weekly cycle of days, but did adjust the day of the month. The Julian calendar had been in use since 45 B.C. and used a standard year of 365 days with every fourth year being a leap year. Over the centuries, the extra days that were slowly added to the calendar caused a problem. When the Gregorian calendar was introduced, a 10-day adjustment was made to the calendar to account for the extra days that had been added to the calendar. Pope Gregory’s decree stated that Thursday, October 4, 1582, should be followed by Friday October 15, 1582.

Because of the adjustment in the calendar, any weekday calculations on dates before 1582 must be adjusted, or considered inaccurate. It’s not likely that you will need to calculate a date that far back for normal programming, but it does make for a good trivia question!

At this juncture, the current method of figuring leap years was introduced. Using the knowledge of the day, it was determined that every fourth year should be a leap year; however, to avoid the addition of extra days caused by the Julian calendar, every year that ended in a even century, such as 1800 and 1900, would not be a leap year. Except, that is, years divisible by 400. Thus the year 2000 is a leap year.

The three different standard Accept statements related to date processing are

000100 Accept The-Date From Date 000101 Accept The-Day From Day 000102 Accept The-Weekday From Day-Of-Week The first returns the date in a format known as Year-Month-Day. The field The-Date is defined as a six-digit numeric field. The first two numbers represent the last two digits of the current year. The next two represent the month, and the last two the day of the month. This format has been in use since the early days of COBOL. When adding the capability for COBOL to retrieve the current date with a four-digit year, the standards committee had the foresight not to change the behavior of these features. Doing so would have broken countless programs. Instead, the committee devised another, better way to handle the situation.

The second format returns the Julian date. The Julian date is a five-digit numeric field. It contains the two-digit year and a three-digit number corresponding to the day of the year. January 1 is day 1; December 31, in a non-leap year, is day 365. In years with a leap year, the last day is 366. Programmers frequently used this format because it took up little of the precious memory and disk storage that was available in early computing.

The third format returns the current day of the week. The value is a single-digit numeric field. For example, 1 is returned for Monday, 2 for Tuesday, and 3 for Wednesday. This format makes it easy to set up a table in working storage that can be referenced to display the name of the present weekday on your screens and on your reports.

The new method for retrieving the current system date and time uses a new feature called an Intrinsic Function. This hour covers only the date-related Functions. The remainder of these very powerful and useful Functions are covered in Hour 22, “Other Intrinsic Functions.”

The Current-Date Intrinsic Function Intrinsic Functions are used like literals. They are invoked by coding the word Function followed by the name of the Intrinsic Function to be used. The Function for returning the current system date and time is Current-Date. Function Current-Date is one of the few Intrinsic Functions that return an alphanumeric value. This Function returns a field that is 21 characters long. The first eight positions are the current date in Year-Month-Day format, using four digits to represent the year. The next eight positions represent the current system time in Hour-Minute-Second-Hundredths format. The final five characters return the offset from Greenwich mean time (GMT) for time-zone conversion. GMT is the accepted baseline for all time-zone calculations. In computing environments where this value is not available, it is not returned. In a Windows NT or Windows 95 environment, the Fujitsu compiler returns the offset from GMT.

Run the small program in Listing 21.1 and examine the results.

Listing 21.1 Using the Current-Date Intrinsic Function

000001 @OPTIONS MAIN,TEST 000002 Identification Division. 000003 Program-Id. Chapt21a. 000004 Environment Division. 000005 Configuration Section. 000006 Source-Computer. IBM-PC. 000007 Object-Computer. IBM-PC. 000008 Data Division. 000009 Working-Storage Section. 000010 01 Current-Date-Group. 000011 03 Todays-Date. 000012 05 Today-YYYY Pic 9(4). 000013 05 Today-MM Pic 9(2). 000014 05 Today-DD Pic 9(2). 000015 03 Time-Now. 000016 05 Time-Hour Pic 99. 000017 05 Time-Minutes Pic 99. 000018 05 Time-Seconds Pic 99. 000019 05 Time-Hundredths Pic 99. 000020 03 GMT-Offset. 000021 05 GMT-Direction Pic X. 000022 05 GMT-Hours Pic 99. 000023 05 GMT-Minutes Pic 99. 000024 Procedure Division. 000025 Chapt21a. 000026 Move Function Current-Date To Current-Date-Group 000027 Display “Today = “ Todays-Date 000028 Display “Time = “ Time-Now 000029 Display “GMT offset = “ GMT-Offset 000030 Stop Run 000031 . The field Current-Date-Group is further divided into the individual fields. Dividing the group in this manner gives you access to each field individually. The GMT-Direction is either a plus sign or a minus sign (+ or -), indicating the conversion that was applied to GMT to achieve local time. Therefore, to convert back to GMT, you must adjust the time in the opposite direction. If the GMT-Direction field is - and the GMT-Hours field is 5, you must add 5 hours to the current time to arrive at GMT.

If you want to use the Current-Date Intrinsic Function but require only the date, not the time values, you can use reference modification. For example, you can code:

000101 Move Function Current-Date (1:8) to Date-Only When using the current date for other than cosmetic reasons, it is best to use the Current-Date Intrinsic Function.

Days Between Dates One task frequently required when working with dates is computing the number of days between dates. This value can be useful in a number of applications. For example, you might require a dealer to bring in new merchandise every 90 days. To derive the next date that a dealer needs to add merchandise, you can add 90 days to the last date the dealer did so. When working with a date in Year-Month-Day format, adding days can be a daunting task.

Adding 90 days might not seem to be a difficult calculation. Simply add 3 months, and that date should be close enough. But many applications require more precision. For instance, you might be writing a program for an ice cream factory. The ice cream might have a shelf life of 37 days. This number of days must be added to the date of manufacture to determine the expiration date.

Another task might be determining the age of an item. Given two dates in Year-Month-Day format, you might need to determine the age of the item.

COBOL provides some date-related Intrinsic Functions that make these types of computations easy to accomplish. These Functions are Integer-Of-Date and Date-Of-Integer. Integer-Of-Date accepts a single argument: the date in Year-Month-Day format, using a four-digit year. The Function returns the number of days since December 31, 1600. Day 1 is January 1, 1601. The standards committee chose this date because integer day 1, January 1, 1601, is a Monday. Monday is day 1 in the Day-Of-Week format of the Accept verb.

When arguments are specified with Intrinsic Functions, the argument follows the Function name and is enclosed in parentheses. The numeric-returning Intrinsic Functions, such as Integer-Of-Date and Date-Of-Integer, must be used in a mathematical statement—that is, within a mathematical expression such as Compute. Unlike the alphanumeric-returning Current-Date Function, you cannot use these Functions in a Move statement. Listing 21.2 shows the conversion of 12/31/1999 into an integer date.

Listing 21.2 Integer-of-Date Example

000001 @OPTIONS MAIN,TEST 000002 Identification Division. 000003 Program-Id. Chapt21b. 000004 Environment Division. 000005 Configuration Section. 000006 Source-Computer. IBM-PC. 000007 Object-Computer. IBM-PC. 000008 Data Division. 000009 Working-Storage Section. 000010 01 Integer-Version-Of-Date Pic 9(7) Value Zeros. 000011 01 Date-To-Convert Pic 9(8) Value 19991231. 000012 Procedure Division. 000013 Chapt21b. 000014 Compute Integer-Version-Of-Date = 000015 Function Integer-Of-Date (Date-To-Convert) 000016 Display “Integer Date Version of “ Date-To-Convert 000017 “ is “ Integer-Version-Of-Date 000018 . You can use the opposite procedure to convert a date from an integer date to a regular Gregorian date in the format YYYYMMDD.

000019 Compute Date-To-Convert = 000020 Function Date-Of-Integer (Integer-Version-Of-Date) Determining the days between particular dates becomes easy. Simply convert each date to an integer date and compute the difference. Likewise, if you want to compute a date that is a certain number of days in the future, convert the date to an integer, add the number of days, and reconvert the result to a date.

The program in Listing 21.3 will Accept two dates and reports the number of days between them. Try compiling it and determining how many days old you are!

Listing 21.3 Days Between Dates

000001 @OPTIONS MAIN,TEST 000002 Identification Division. 000003 Program-Id. Chapt21c. 000004* Days Between Dates 000005 Environment Division. 000006 Configuration Section. 000007 Source-Computer. IBM-PC. 000008 Object-Computer. IBM-PC. 000009 Data Division. 000010 Working-Storage Section. 000011 01 First-Date Value Zeros. 000012 03 Date-MM Pic 99. 000013 03 Date-DD Pic 99.

000014 03 Date-YYYY Pic 9(4). 000015 01 Second-Date Value Zeros. 000016 03 Date-MM Pic 99. 000017 03 Date-DD Pic 99. 000018 03 Date-YYYY Pic 9(4). 000019 01 Days-Between Pic S9(12) Value Zeros. 000020 01 Integer-First-Date Pic 9(12). 000021 01 Integer-Second-Date Pic 9(12). 000022 01 Date-Formatting-Items. 000023 03 YYYYMMDD-Format-Date. 000024 05 Date-YYYY Pic 9(4). 000025 05 Date-MM Pic 99. 000026 05 Date-DD Pic 99. 000027 03 YYYYMMDD-Format-Date-N Redefines 000028 YYYYMMDD-Format-Date Pic 9(8). 000029 03 Format-Indicator-F Pic X(8) Value “MMDDYYYY”. 000030 03 Format-Indicator-S Pic X(8) Value “MMDDYYYY”. 000031 Screen Section. 000032 01 Date-Entry Blank Screen Auto. 000033 03 Line 01 Column 01 Value “Enter First Date: “. 000034 03 Line 01 Column 21 Pic X(8) From Format-Indicator-F 000035 To First-Date. 000036 03 Line 03 Column 01 Value “Enter Second Date: “. 000037 03 Line 03 Column 21 Pic X(8) From Format-Indicator-S 000038 To Second-Date. 000039 03 Line 05 Column 01 Value “Days between dates: “. 000040 03 Line 05 Column 21 Pic -Zzz,ZZ9 From Days-Between. 000041 Procedure Division. 000042 Chapt21c-Start. 000043 Display Date-Entry 000044 Accept Date-Entry 000045 Move Corresponding First-Date To YYYYMMDD-Format-Date 000046 Compute Integer-First-Date = 000047 Function Integer-Of-Date (YYYYMMDD-Format-Date-N) 000048 Move First-Date To Format-Indicator-F 000049 Move Corresponding Second-Date To YYYYMMDD-Format-Date 000050 Compute Integer-Second-Date = 000051 Function Integer-Of-Date (YYYYMMDD-Format-Date-N) 000052 Move Second-Date To Format-Indicator-S 000053 Compute Days-Between = Integer-Second-Date - 000054 Integer-First-Date 000055 Display Date-Entry 000056 Stop Run 000057 . When you run the program, notice the use of the separate From and To fields in the screen definition. This syntax allows you to prompt the user for the proper date format.

Determining the Day of the Week for a Particular Date The Integer-Of-Date Function can also be used in a calculation to determine the day of the week for a particular day. Because day 1 in the COBOL calendar, January 1, 1601, is a Monday, figuring the day of the week for any other, later date is fairly easy. All you have to do is divide the integer value of the date by 7—the number of days in the week— and examine the remainder. If the remainder is 1, the day of the week is Monday; 2 is Tuesday, 3 is Wednesday, and so on. If the day is Sunday, the remainder is zeros. The modification of Listing 21.3 that appears in Listing 21.4 determines and displays the weekday of the two dates entered. This program uses a table to reference the descriptions for the days. Because Sunday is day 0 after the division, the program adds 1 to the remainder to properly reference a table. The number of weeks is computed, but not used.

Listing 21.4 Days Between Dates, with Weekday

000001 @OPTIONS MAIN,TEST 000002 Identification Division. 000003 Program-Id. Chapt21d. 000004* Days Between Dates, With Weekday 000005 Environment Division. 000006 Configuration Section. 000007 Source-Computer. IBM-PC. 000008 Object-Computer. IBM-PC. 000009 Data Division. 000010 Working-Storage Section. 000011 01 First-Date Value Zeros. 000012 03 Date-MM Pic 99. 000013 03 Date-DD Pic 99. 000014 03 Date-YYYY Pic 9(4). 000015 01 Second-Date Value Zeros. 000016 03 Date-MM Pic 99. 000017 03 Date-DD Pic 99. 000018 03 Date-YYYY Pic 9(4). 000019 01 Days-Between Pic S9(12). 000020 01 Integer-First-Date Pic 9(12). 000021 01 Integer-Second-Date Pic 9(12). 000022 01 Date-Formatting-Items. 000023 03 YYYYMMDD-Format-Date. 000024 05 Date-YYYY Pic 9(4). 000025 05 Date-MM Pic 99. 000026 05 Date-DD Pic 99. 000027 03 YYYYMMDD-Format-Date-N 000028 Redefines YYYYMMDD-Format-Date Pic 9(8). 000029 03 Format-Indicator-F Pic X(8) Value “MMDDYYYY”. 000030 03 Format-Indicator-S Pic X(8) Value “MMDDYYYY”. 000031 01 Weekday-First Pic X(9) Value Spaces. 000032 01 Weekday-Second Pic X(9) Value Spaces. 000033 01 Weekday-Table-Area.

000034 03 Weekday-Table-Values. 000035 05 Filler Pic X(27) Value “Sunday Monday Tuesday”. 000036 05 Filler Pic X(27) Value “WednesdayThursday Friday”. 000037 05 Filler Pic X(9) Value “Saturday”. 000038 03 Weekday-Table Redefines Weekday-Table-Values. 000039 05 The-Day Pic X(9) Occurs 7 Times. 000040 01 Weeks Pic 9(12) Value Zeros. 000041 01 Remainder-Days Pic 9. 000042 Screen Section. 000043 01 Date-Entry Blank Screen Auto. 000044 03 Line 01 Column 01 Value “Enter First Date: “. 000045 03 Line 01 Column 21 Pic X(8) From Format-Indicator-F 000046 To First-Date. 000047 03 Line 01 Column 30 Pic X(9) From Weekday-First. 000048 03 Line 03 Column 01 Value “Enter Second Date: “. 000049 03 Line 03 Column 21 Pic X(8) From Format-Indicator-S 000050 To Second-Date. 000051 03 Line 03 Column 30 Pic X(9) From Weekday-Second. 000052 03 Line 05 Column 01 Value “Days between dates: “. 000053 03 Line 05 Column 21 Pic -Zzz,ZZ9 From Days-Between. 000054 Procedure Division. 000055 Chapt21d-Start. 000056 Display Date-Entry 000057 Accept Date-Entry 000058 Move Corresponding First-Date To YYYYMMDD-Format-Date 000059 Compute Integer-First-Date = 000060 Function Integer-Of-Date (YYYYMMDD-Format-Date-N) 000061 Move First-Date To Format-Indicator-F 000062 Move Corresponding Second-Date To YYYYMMDD-Format-Date 000063 Compute Integer-Second-Date = 000064 Function Integer-Of-Date (YYYYMMDD-Format-Date-N) 000065 Move Second-Date To Format-Indicator-S 000066 Compute Days-Between = 000067 Integer-Second-Date - Integer-First-Date 000068 Divide Integer-First-Date By 7 Giving Weeks 000069 Remainder Remainder-Days 000070 Add 1 To Remainder-Days 000071 Move The-Day (Remainder-Days) To Weekday-First 000072 Divide Integer-Second-Date By 7 Giving Weeks 000073 Remainder Remainder-Days 000074 Add 1 To Remainder-Days 000075 Move The-Day (Remainder-Days) To Weekday-Second 000076 Display Date-Entry 000077 Stop Run 000078 . Determining the weekday of any given date is an easy operation in COBOL. An even easier method that uses another COBOL-provided Intrinsic Function is demonstrated later in this hour.

Validating Dates In Hour 18, “Master File Updating,” you wrote a transaction file data entry program. This program used transaction dates. No checks were performed on the dates that the user entered, and invalid data could enter the transaction file.

Whenever possible you should ensure that invalid data cannot enter the systems that you design and code. Correcting invalid data after it has been accepted can be a very time-consuming and complex task. Prevention is the order of the day.

Dates are a particularly sensitive area for business. Ensuring that the dates entered are valid is very important. Date validation is simple to accomplish.

When validating a date, you must first ensure that it has been entered in the proper format by checking the values in the individual fields that make up the date. First, check the month value to determine whether it is between 1 and 12. Any value outside that range is obviously invalid.

Then you must check the value of the day to determine whether it falls within the prescribed value for the particular month with which it is associated. Each month, with the exception of February, has a set number of days. A table of maximum day values is the simplest method of validating the day.

To properly validate days in February, you must determine whether the year being checked is a leap year. The rules for determining a leap year are simple. Any year evenly divisible by 4, except those years evenly divisible by 100 and not evenly divisible by 400, is a leap year. The year 2000 is a leap year because it is evenly divisible by 400. The year 1900, although evenly divisible by 4, was not a leap year because it was evenly divisible by 100 and not by 400.

After you determine that the month and day are valid, you can check the full date to determine whether it falls within your desired range. For example, you might want to Accept a date and then ensure that it falls within 30 days of the current date. Any date that falls outside that range is invalid.

After determining that the month and day are valid, you can convert the day to an integer and check it against the integer value of the current date.

The program in Listing 21.5 accepts a date in MM/DD/YYYY format and validates the date. It then checks to ensure that the date is within 30 days of the current date. The validity and range are reported on the screen before the program ends.

Image

One thing you should do before using the Intrinsic Function for converting the entered date to an integer is ensure that the year entered is 1601 or greater. Any invalid value passed as an argument to the Intrinsic Function Integer-Of-Date causes the Function to abnormally terminate your program.

Listing 21.5 Date Validation

000001 @OPTIONS MAIN,TEST 000002 Identification Division. 000003 Program-Id. Chapt21e. 000004* Validate A Date 000005 Environment Division. 000006 Configuration Section. 000007 Source-Computer. IBM-PC. 000008 Object-Computer. IBM-PC. 000009 Data Division. 000010 Working-Storage Section. 000011 01 Date-Validation-Work-Fields. 000012 03 Date-To-Validate Pic 9(8) Value Zeros. 000013 03 Date-To-Validate-X Redefines Date-To-Validate. 000014 05 Date-MM Pic 99. 000015 05 Date-DD Pic 99. 000016 05 Date-YYYY Pic 9(4). 000017 03 YYYYMMDD-Format-Date Pic 9(8) Value Zeros. 000018 03 YYYYMMDD-Format-Date-X Redefines YYYYMMDD-Format-Date. 000019 05 Date-YYYY Pic 9(4). 000020 05 Date-MM Pic 99. 000021 05 Date-DD Pic 99. The Day-Table has an entry containing the number of days in the corresponding month. Only the second entry, February, requires modification if the year being tested is a leap year.

000022 03 Day-Table-Values Pic X(24) Value 000023 “312831303130313130313031”. 000024 03 Day-Table Redefines Day-Table-Values. 000025 05 Days-In-Month Pic 99 Occurs 12 Times. The work fields below are used in the process of validating the dates. The remainder fields are used with division statements to determine whether the year in question is a leap year.

000026 01 Valid-Status Pic X(40) Value Spaces. 000027 01 Work-Number Pic 9(5) Value Zeros. 000028 01 Work-Remainder Pic 9(5) Value Zeros. 000029 01 Work-Remainder-100 Pic 9(5) Value Zeros. 000030 01 Work-Remainder-400 Pic 9(5) Value Zeros. 000031 01 Today-Date Pic 9(8) Value Zeros. 000032 01 Today-Integer Pic 9(7) Value Zeros. 000033 01 Test-Integer Pic 9(7) Value Zeros. 000034 01 Test-Range Pic 9(7) Value Zeros. 000035 Screen Section. 000036 01 Date-Entry Blank Screen Auto. 000037 03 Line 01 Column 01 Value “Enter Date: “. 000038 03 Line 01 Column 13 Pic 99/99/9999 Using Date-To-Validate. 000039 03 Line 01 Column 24 Pic X(40) From Valid-Status. 000040 Procedure Division. 000041 Chapt21e-Start. 000042 Display Date-Entry 000043 Accept Date-Entry The first part of the program determines whether the year entered is a leap year. The first step is to set up the three conditions that must be checked.

000044 Divide Date-YYYY Of Date-To-Validate-X By 4 000045 Giving Work-Number Remainder 000046 Work-Remainder 000047 Divide Date-YYYY Of Date-To-Validate-X By 100 000048 Giving Work-Number Remainder 000049 Work-Remainder-100 000050 Divide Date-YYYY Of Date-To-Validate-X By 400 000051 Giving Work-Number Remainder 000052 Work-Remainder-400 The conditions are then tested. If Work-Remainder is zeros, the date was divisible by 4, which it must be to be a leap year. Then if the date is not divisible by 100 or if the date is divisible by 400, it is a leap year. The appropriate number of days is moved to the table for February.

000053 If Work-Remainder = Zeros And 000054 (Work-Remainder-100 Not = Zeros Or 000055 Work-Remainder-400 = Zeros) 000056 Move 29 To Days-In-Month (2) 000057 Else 000058 Move 28 To Days-In-Month (2) 000059 End-If The conditions that make the date an invalid date are checked. If any of these conditions is true, the date is invalid. To be valid, the month must be between 1 and 12. The year must be greater than 1600 or else the Intrinsic Functions related to Integer-Of-Date fails. The day must be at least 1 and not greater than the maximum number of days in the month.

000060 If Date-MM Of Date-To-Validate-X > 12 Or 000061 Date-MM Of Date-To-Validate-X < 01 Or 000062 Date-YYYY Of Date-To-Validate-X < 1601 Or 000063 Date-DD Of Date-To-Validate-X Not > Zero Or 000064 Date-DD Of Date-To-Validate-X > 000065 Days-In-Month (Date-MM Of Date-To-Validate-X) 000066 Move “Invalid Date” To Valid-Status 000067 End-If If the date was not marked invalid by a message in the Valid-Status field, then the number of days between the dates can be checked.

When comparing the two dates, you will have no idea which is greater. When you do the subtraction of the two integer dates, you could end up with either a positive or a negative number. To make the comparison easy, the result of the subtraction is stored in an unsigned field. This step causes the value to be stored without a sign and treated in comparisons as a positive number.

000068 If Valid-Status = Spaces 000069 Move Corresponding Date-To-Validate-X To 000070 YYYYMMDD-Format-Date-X 000071 Move Function Current-Date (1:8) To Today-Date 000072 Compute Test-Range = 000073 Function Integer-Of-Date (YYYYMMDD-Format-Date) - 000074 Function Integer-Of-Date (Today-Date) 000075 If Test-Range > 30 000076 Move “Date Valid, but out of Range” To Valid-Status 000077 End-If 000078 End-If If there were no errors, a message to that effect is displayed for the user.

000079 If Valid-Status = Spaces 000080 Move “Date Valid and Within Range” To Valid-Status 000081 End-If 000082 Display Date-Entry 000083 . The previous examples use the remainder of a division to calculate the day of the week and to determine whether a year is a leap year. In COBOL a simpler method can achieve the same results. When you want to use a remainder only and are not concerned about the whole result of the division, you can use the Intrinsic Function Rem. Rem returns the remainder of the first argument divided by the second. When you are concerned only with the remainder, using the Function Rem is more efficient than coding the necessary Working-Storage and Divide statement.

Function Rem simplifies the day of the week calculation so that it consists of only the following lines of code:

000065 Compute Remainder-Days = 000066 (Function Rem (Integer-First-Date 7) + 1) 000067 Move The-Day (Remainder-Days) To Weekday-First Notice that the arguments for the Function are enclosed in parentheses after the Function name.

Another interesting calculation is the conversion from local time to GMT using the values returned from the Current-Date Intrinsic Function. The problem in this conversion comes from the fact that when you subtract or add the time differential, the date may change. Doing math on time fields is tricky under normal circumstances. With the added complexity of a possibly changing date, the task can seem rather challenging. Times are tricky to work with because they are not normal base 10 numbers. When you add to the minutes, anything over 59 requires the hour to be incremented by 1. If you are subtracting and need to borrow from the hours, you must add 59 to the minutes, not 10 as in more conventional math. Consequently, normal computational formulas won’t solve the problem.

Image

When multiple arguments are specified with an Intrinsic Function, they may be separated by a comma. This visual clue sometimes makes the arguments easier to pick out when examining source code. For example, the Function Rem noted above, can be coded as Function Rem (Integer-First-Date, 7).

One simple way to solve the problem is to convert the current time into seconds since midnight 12/31/1600. The solution is relatively easy if you use these equivalencies: 86,400 seconds in a day; 3,600 seconds in an hour; and 60 seconds in a minute. Multiply the date by 86,400; the hour by 3,600; and the minutes by 60; then add the current time seconds to the result. The current time is now in seconds. Perform the same type of math against the GMT offset, as reported by the Current-Date Intrinsic Function, and either add or subtract the amount of seconds from the current date in seconds.

The only remaining difficulty is to return the resulting seconds to a conventional date and time. Listing 21.6 shows the program required to perform the calculation. Find the number of the day by dividing the resulting seconds by 86,400 and save the remainder, as it is the time. Convert this integer date to a Gregorian date. Divide the remaining seconds by 3,600 to find the hour, again saving the remainder. Then divide the remainder of that calculation by 60 to find the minutes. The remainder of this computation is the seconds! Simple.

Listing 21.6 Convert Local Time to Gmt

000001 @OPTIONS MAIN,TEST 000002 Identification Division. 000003 Program-Id. Chapt21g. 000004* Convert Local Time To Gmt 000005 Environment Division. 000006 Configuration Section. 000007 Source-Computer. IBM-PC. 000008 Object-Computer. IBM-PC. 000009 Data Division. 000010 Working-Storage Section. 000011 01 Current-Date-Group. 000012 03 Todays-Date. 000013 05 Today-YYYY Pic 9(4). 000014 05 Today-MM Pic 9(2). 000015 05 Today-DD Pic 9(2). 000016 03 Todays-Date-N Redefines Todays-Date Pic 9(8). 000017 03 Time-Now. 000018 05 Time-Hour Pic 99. 000019 05 Time-Minutes Pic 99. 000020 05 Time-Seconds Pic 99. 000021 05 Time-Hundredths Pic 99. 000022 03 GMT-Offset. 000023 05 GMT-Direction Pic X. 000024 05 GMT-Hours Pic 99. 000025 05 GMT-Minutes Pic 99. 000026 01 Display-Date. 000027 03 Today-MM Pic 9(2). 000028 03 Filler Pic X Value “/”. 000029 03 Today-DD Pic 9(2). 000030 03 Filler Pic X Value “/”. 000031 03 Today-YYYY Pic 9(4). 000032 01 Display-Time. 000033 03 Time-Hour Pic 99. 000034 03 Filler Pic X Value “:”. 000035 03 Time-Minutes Pic 99. 000036 03 Filler Pic X Value “:”. 000037 03 Time-Seconds Pic 99. 000038 01 Total-Seconds Pic 9(15) Value Zeros. 000039 01 Work-Number Pic 9(15) Value Zeros. 000040 01 Work-Remainder Pic 9(15) Value Zeros. 000041 01 GMT-Offset Pic 9(15) Value Zeros. 000042 Procedure Division. 000043 Chapt21g. 000044 Move Function Current-Date To Current-Date-Group 000045* Convert Today To Seconds 000046 Compute Work-Number = 000047 Function Integer-Of-Date (Todays-Date-N)

000048 Compute Total-Seconds = (Work-Number * 86400) + 000049 (Time-Hour Of Time-Now * 3600) + 000050 (Time-Minutes Of Time-Now * 60) + 000051 Time-Seconds Of Time-Now 000052 Compute Work-Number = (GMT-Hours * 3600) + 000053 (GMT-Minutes * 60) 000054* We Need To Change By The Opposite Of The Direction From Gmt 000055 If GMT-Direction = “+” 000056 Subtract Work-Number From Total-Seconds 000057 Else 000058 Add Work-Number To Total-Seconds 000059 End-If 000060* Convert The Time In Seconds Back To A Date And Time 000061 Divide Total-Seconds By 86400 Giving Work-Number 000062 Remainder Work-Remainder 000063 Compute Todays-Date-N = 000064 Function Date-Of-Integer (Work-Number) 000065 Divide Work-Remainder By 3600 Giving Time-Hour Of Time-Now 000066 Remainder Work-Number 000067 Divide Work-Number By 60 Giving Time-Minutes Of Time-Now 000068 Remainder Time-Seconds Of Time-Now Image

This next computation uses the remainder from the last division and stores the new remainder in Work-Number, which is used in the next calculation. Although the names don’t match their Function, this technique saves having to move the fields before the next calculation.

000069 Move Corresponding Todays-Date To Display-Date 000070 Move Corresponding Time-Now To Display-Time 000071 Display “Current GMT “ Display-Date “ “ Display-Time 000072 Stop Run 000073 .

Other Kinds of Dates Occasionally, you may need to use the Julian date instead of the Gregorian date. The Intrinsic Functions provide an easy way to convert to and from the Julian date. These Functions are similar to the Date-Of-Integer and Integer-Of-Date Functions.

The Functions related to the Julian date are Day-Of-Integer and Integer-Of-Day. These Functions make conversion to and from the Gregorian date simple. If you want to convert from Gregorian date, use the Function Integer-Of-Date to find the integer date of the day in question. Then, using that integer, execute the Function Day-Of-Integer. The Julian date is returned in YYYYDDD format, where YYYY is the full four-digit year and DDD is the day of the year.

To convert from Julian date to Gregorian date, use the Function Integer-Of-Day to determine the integer date; then use the Function Date-Of-Integer to find the Gregorian date.

Fun with Dates Now that you know how to do nearly everything there is to do with dates, you can have some fun. You can create your own calendar program. You can determine the holidays and print these on the calendar. Most holidays fall on specific days of the month or on the closest Monday to that day. The only really tricky holiday to figure is the date for Easter.

In 325 A.D., the Council of Nicaea determined that Easter should be celebrated on the first Sunday after the first full moon after the vernal equinox. If the full moon fell on a Sunday, causing it to coincide with the Passover, it would be celebrated the following Sunday.

Problems soon beset this method because of the difference between the solar year and the lunar year, known as the epact. Over time, the difference became increasingly pronounced. It was the problem of fixing the date of Easter that ultimately led to the calendar reform of 1582.

The method for calculating the date of Easter is fairly complex. However, because it has a series of steps that follow a specific set of rules, a program can be created that accurately calculates the date.

The algorithm chosen first appeared in volume 1 of The Art of Computer Programming by Donald Knuth. The steps are as follows:

• First, the current position in the metonic cycle is determined by the remainder of the full four-digit year divided by 19. Every 19 years, the phases of the moon repeat on the same calendar days of the year. This cycle is the metonic cycle, and the result of this computation is known as the “golden number.”

• Next, the century number is determined by dividing the year by 100, disregarding the remainder, and adding 1.

• Next, the number of years that the leap year was dropped in the even centuries is determined. Remember that if the century is divisible by 100 and not by 400, the year, which is divisible by 4, is not a leap year. The number of years in which this condition occurs is determined by multiplying the century previously computed by 3, dividing the result by 4, and subtracting 12. The remainder portion of the division is discarded. After 1900 and until the year 2100, this number is 3—the number of even centuries without a leap year since calendar reform. (Recall that 1600 was a leap year, 1700 was not, 1800 was not, 1900 was not, and 2000 is.)

• A special correction is computed to synchronize Easter with the orbit of the moon. This value is 8 times the century, plus 5, divided by 25. The remainder is discarded, and 5 is subtracted from the result of the division.

• A factor is determined to adjust the date to the next Sunday. This factor is computed by multiplying the full four-digit year by 5 and dividing the result by 4. Again, the remainder is discarded. The number of skipped leap years plus 10 is then subtracted from the result.

• Next, the epact is computed. It is the remainder of 11 times the golden number, plus 20, plus the correction factor, minus the number of skipped leap years, all divided by 30. The epact is always a positive number. If you achieve a negative result, change the sign to positive. In the COBOL program, you can just compute the value into an unsigned field.

• If the epact is 24, or if the epact is 25 and the golden number is greater than 11, 1 is added to the epact.

• The day of the first full moon in March is then computed. This value is 44 minus the epact. If the result of this subtraction is less than 21, then 30 is added to it.

• This day is then advanced to the following Sunday by subtracting the remainder of the sum of this date and the correction factor divided by 7 from the day plus 7. That is, day plus 7 minus remainder, or ((Day + Correction) / 7).

• If this resulting day is greater than 31, then Easter falls in April instead of March and 31 is subtracted from the day.

Taking this type of algorithm and creating a program that performs the task is the COBOL programmer’s job. Chapt21h.Cob, shown in Listing 21.7, computes the date of Easter for any given year.

Listing 21.7 Easter Date Calculation

000001 @OPTIONS MAIN,TEST 000002 Identification Division. 000003 Program-Id. Chapt21h. 000004* Compute The Date Of Easter For The Given Year 000005 Environment Division. 000006 Configuration Section. 000007 Source-Computer. IBM-PC.

000008 Object-Computer. IBM-PC. 000009 Data Division. 000010 Working-Storage Section. 000011 01 Easter-Work-Fields. 000012 03 The-Year Pic 9(4) Value Zeros. 000013 03 Easter-Date Pic 9(8) Value Zeros. 000014 03 Easter-Date-X Redefines Easter-Date. 000015 05 Easter-Month Pic 99. 000016 05 Easter-Day Pic 99. 000017 05 Easter-Year Pic 9(4). 000018 03 Golden-Number Pic 9(6). 000019 03 Century Pic 9(3). 000020 03 Skipped-Leap-Year Pic 9(6). 000021 03 Correction Pic 9(8). 000022 03 Factor Pic 9(8). 000023 03 Epact Pic 9(8). 000024 01 Temp-Work Pic 9(8). 000025 01 Temp-Work-1 Pic 9(8). 000026 Screen Section. 000027 01 Date-Entry Blank Screen Auto. 000028 03 Line 01 Column 01 Value “Enter Year: “. 000029 03 Line 01 Column 14 Pic 9(4) Using The-Year. 000030 03 Line 03 Column 01 Value “Easter is: “. 000031 03 Line 03 Column 15 Pic 99/99/9999 From Easter-Date. 000032 Procedure Division. 000033 Chapt21h-Start. 000034 Display Date-Entry 000035 Accept Date-Entry 000036 Move The-Year To Easter-Year 000037* 000038 Compute Golden-Number = Function Rem (The-Year 19) 000039 Add 1 To Golden-Number 000040* 000041 Divide The-Year By 100 Giving Century 000042 Add 1 To Century 000043* 000044 Compute Temp-Work = 3 * Century 000045 Divide Temp-Work By 4 Giving Skipped-Leap-Year 000046 Subtract 12 From Skipped-Leap-Year 000047* 000048 Compute Temp-Work = (8 * Century) + 5 000049 Divide Temp-Work By 25 Giving Correction 000050 Subtract 5 From Correction 000051* 000052 Compute Temp-Work = 5 * The-Year 000053 Divide Temp-Work By 4 Giving Factor 000054 Subtract Skipped-Leap-Year From Factor 000055 Subtract 10 From Factor 000056*

000057 Compute Temp-Work = (11 * Golden-Number) + 20 000058 + Correction - Skipped-Leap-Year 000059 Compute Epact = Function Rem (Temp-Work 30) 000060* 000061 If Epact = 25 And Golden-Number > 11 Or 000062 Epact = 24 000063 Add 1 To Epact 000064 End-If 000065* 000066 Compute Temp-Work = 44 - Epact 000067 If Temp-Work < 21 000068 Add 30 To Temp-Work 000069 End-If 000070* 000071 Compute Temp-Work-1 = Factor + Temp-Work 000072 Compute Easter-Day = Temp-Work + 7 - 000073 Function Rem (Temp-Work-1 7) 000074* 000075 If Easter-Day > 31 000076 Move 4 To Easter-Month 000077 Subtract 31 From Easter-Day 000078 Else 000079 Move 3 To Easter-Month 000080 End-If 000081 Move The-Year To Easter-Year 000082* 000083 Display Date-Entry 000084 Stop Run 000085 .

Summary In this hour, you learned the following:

• COBOL provides several powerful Functions for date processing.

• Today’s date, time, and offset from Greenwich mean time can be determined with the Intrinsic Function Current-Date.

• When using Intrinsic Functions, the argument or arguments are enclosed in parentheses after the name of the Function.

• The Function Integer-Of-Date returns a value that is the number of days since December 31, 1600, for the date used as the argument.

• When using the Intrinsic Functions for dates, the Gregorian date format is YYYYMMDD and the Julian date format is YYYYDDD.

• The current state of the calendar is directly related to the 1582 calendar reform that corrected the number of days in the year, by adjusting the years that have a leap year, in an effort to solidify and correct the calculation of Easter.

• You can use the Intrinsic Function Rem instead of the Divide statement to find the remainder of a division.

Q&B Q Why did the standards committee choose January 1, 1601, as day 1 in the COBOL calendar?

A It was the closest year to calendar reform that began on a Monday. When accepting the current weekday from the system, 1 is the value returned for Monday.

Q When I want to figure out what the date is 90 days from now, what is the easiest method?

A Convert the date to an integer, using the Function Integer-Of-Date, and then add 90. Convert that number back to a date using the Function Date-Of-Integer.

Q What happens if I use an invalid date as an argument for one of the date Intrinsic Functions?

A The Function fails, and in most COBOL implementations your program ends abnormally.

Q My program won’t compile when I try to code Move Function Integer-Of-Date (The-Date) to Integer-Date. Why not?

A Numeric Intrinsic Functions must be used in mathematical expressions.

Workshop To help reinforce your understanding of the material presented in this hour, refer to the section “Quiz and Exercise Questions and Answers” that can be found on the CD. This section contains quiz questions and exercises for you to complete, as well as the corresponding answers.

Fair Use Sources

COBOL: COBOL Fundamentals, COBOL Inventor - COBOL Language Designer: 1959 by Howard Bromberg, Norman Discount, Vernon Reeves, Jean E. Sammet, William Selden, Gertrude Tierney, with indirect influence from Grace Hopper, CODASYL, ANSI COBOL, ISO/IEC COBOL; Modern COBOL - Legacy COBOL, IBM COBOL, COBOL keywords, COBOL data structures - COBOL algorithms, COBOL syntax, Visual COBOL, COBOL on Windows, COBOL on Linux, COBOL on UNIX, COBOL on macOS, Mainframe COBOL, IBM i COBOL, IBM Mainframe DevOps, COBOL Standards, COBOL Paradigms (Imperative COBOL, Procedural COBOL, Object-Oriented COBOL - COBOL OOP, Functional COBOL), COBOL syntax, COBOL installation, COBOL containerization, COBOL configuration, COBOL compilers, COBOL IDEs, COBOL development tools, COBOL DevOps - COBOL SRE, COBOL data science - COBOL DataOps, COBOL machine learning, COBOL deep learning, COBOL concurrency, COBOL history, COBOL bibliography, COBOL glossary, COBOL topics, COBOL courses, COBOL Standard Library, COBOL libraries, COBOL frameworks, COBOL research, Grace Hopper, COBOL GitHub, Written in COBOL, COBOL popularity, COBOL Awesome list, COBOL Versions. (navbar_cobol)


© 1994 - 2024 Cloud Monk Losang Jinpa or Fair Use. Disclaimers

SYI LU SENG E MU CHYWE YE. NAN. WEI LA YE. WEI LA YE. SA WA HE.


sams_teach_yourself_cobol_in_24_hours_-_hour_21_date_manipulation.txt · Last modified: 2024/04/28 03:37 (external edit)