PreviousThe Worksheet Fixing Date ProblemsNext

Chapter 12: Year 2000 Problems and Solutions

This chapter explains some of the basic year 2000 problems and the principles for fixing them using the windowing technique. It is equally suitable as background information whether you are verifying or remediating applications.

12.1 Year 2000 Problems in COBOL Programs

The COBOL constructions that can cause a year 2000 problem are:

In addition, although CALL statements do not in themselves cause a problem, if you pass year data items as parameters to the called programs, you will need to check and fix those programs as necessary.

To see sample code showing these and more complex problems, see the gotchas.cbl sample program within the sfplus\revolve\sample directory.

12.2 SmartFix Assumptions and Restrictions

SmartFix generates fixes based on the year type of the suspect data items and applies the fixes according to the type of suspect statement, as follows:

SmartFix provides a fix for only some types of statements, and sets the fix status of the statement accordingly, as follows:


Note: By default, SmartFix inserts COBOL code that conforms to the ANSI '85 standard. You can for fix code that conforms to the ANSI '74 standard. This fix code is in the ANS74 macro library and is available from the Fix Options tab of the worksheet Options.


SmartFix provides fixes for:

Restrictions:

SmartFix does not provide fixes for:

12.3 Comparisons

Problem:

Comparisons can occur in EVALUATE, IF, PERFORM and SEARCH statements. SmartFix does not handle SEARCH statements at all.

The following statement compares two years. If the two years are in different centuries, the wrong result is produced. For example:

     if yy1 > yy2 
*    if 05 > 98       *> wrong result
*    if 2005 > 1998   *> correct result 

Note that if the comparison is comparing for equality or non-equality, there is not a logic problem at the century boundary.

Find:
  1. At the worksheet, click Display Filters.
  2. Click Defaults.
  3. In Statement, specify IF*.
  4. Click OK.

You now need to search for the PERFORM, EVALUATE and SEARCH statements in much the same way.

Fix:
*     if yy1 > yy2         *> original IF statement 
1     expand yy1 into ccyy1   *> ready to compare in line 3
2     expand yy2 into ccyy2   *> ready to compare in line 3
3     if ccyy1 > ccyy2     *> compare expanded data items
Lines 1 and 2 The two date data items need expanding ready for the comparison in the IF statement in line 3.
Line 3 The IF statement needs to use the expanded versions of the two date data items.
How to fix:

SmartFix fixes any comparison that has an operand with a year type allocated. SmartFix uses the macros for each operand's year type and handles the statement as follows:

  1. Expands each date data item according to its year type.

  2. Replaces the date data items in the IF statement with their expanded versions.

SmartFix does not do anything with the expanded date data items after the statement, since the operands were not changed in the statement and the originals are still valid.

Comments:

12.4 PERFORM Statements

The PERFORM statement header can involve a comparison in its UNTIL clause, and an arithmetic modification in its VARYING clause. Both the comparison and the modification can cause logic problems if the data items involved represent dates.

SmartFix automatically generates a fix for the PERFORM statement header so that the UNTIL condition and the VARYING clauses are evaluated correctly the first time through the PERFORM loop. The compared data items are expanded before the header, and the varied operand is expanded before the header and contracted after it.

However a complication arises in fixing PERFORM statements because the date data items in the PERFORM statement header might be modified during the performed code and so they need fixing every time through the PERFORM loop. In these situations, you need to manually add code at the end of the PERFORM loop to ensure the date data items are up to date when they tested and varied again in the UNTIL and VARYING clauses of the PERFORM statement header.

12.4.1 PERFORM UNTIL Condition

Problem:

In a PERFORM UNTIL statement, two operands are compared, and one or other of them will be modified within the performed code before they are compared again.

    perform until yy1 > yy2 
        . . . performed code . . .
    end-perform

The initial comparison can be fixed like any other comparison, by expanding the date data items before the comparison. The complication in a PERFORM statement is that the date data items might change each time through the loop and so they need re-expanding every time.

Find:

  1. At the worksheet, click Display Filters.
  2. Click Defaults.
  3. In Statement, specify PERFORM*.
  4. Click OK.
Fix:
1    expand yy1 into ccyy1      *> ready to compare in line 3
2    expand yy2 into ccyy2      *> ready to compare in line 3
3    perform until ccyy1 > ccyy2  *> compare expanded dates
         . . . performed code . . .
11       expand yy1 into ccyy1    *> in case yy1 has changed
12       expand yy2 into ccyy2    *> in case yy2 has changed
13   end-perform 
Lines 1 and 2 The two date data items need expanding ready for the first comparison in the UNTIL clause in line 3.
Line 3 The UNTIL clause needs to use the expanded versions of the two date data items.
Lines 11 and 12 The date data items might have been modified in the performed code since the PERFORM statement header. In case they have, they need re-expanding, ready for the next comparison in the UNTIL clause.
How to fix:

SmartFix automatically generates a fix that:

You need to manually edit the code to expand the date data items at the end of the performed code, immediately before the END-PERFORM statement. If the performed code modifies only one of the date data items, you need expand that one only. See lines 11 and 12 in the fix above.

12.4.2 PERFORM VARYING ... Where the Varied Item is not Compared

Problem:

In a PERFORM VARYING . . . statement, an operand is assigned an initial value at the start of the loop and is varied every time through the loop. This section describes the case where the varied operand is not involved in the comparison in the UNTIL clause.

    perform varying yy1 from yy2 by 1 until yy3 > yy4
        . . . performed code . . .
    end-perform

This VARYING clause assigns the date data item, yy1, with an initial value and then modifies that date data item each time through the loop. The initial assignment does not cause a problem. The modification, however, might involve problematic arithmetic and so needs fixing.

Find:

  1. At the worksheet, click Display Filters.
  2. Click Defaults.
  3. In Statement, specify PERFORM*.
  4. Click OK.
Fix:
1    expand yy2 into ccyy2     *> ready to assign in line 4
2    expand yy3 into ccyy3     *> ready to compare in line 4
3    expand yy4 into ccyy4     *> ready to compare in line 4
4    perform varying ccyy1 from ccyy2 by 1 until ccyy3 > ccyy4
5        contract ccyy1 into yy1     *>since ccyy1 has changed
         . . . performed code . . .
11       expand yy1 into ccyy1       *> in case yy1 has changed
12       expand yy2 into ccyy2       *> in case yy2 has changed
13       expand yy3 into ccyy3       *> in case yy3 has changed
14    end-perform 
15    contract ccyy1 into yy1        *> since ccyy1 has changed
Line 1 In theory, this date data item does not need expanding. However, for practical purposes it does, because it is used to assign an expanded date to the date data item ccyy1. Note that the date data item, yy1, does not need expanding initially, since it is assigned its value in line 4.
Lines 2 and 3 The two compared date data items need expanding ready for the first comparison in the UNTIL clause in line 4.
Line 4 Although, the expanded ccyy1 is not needed for the assignment in the first execution of the PERFORM statement, it is needed in subsequent executions, where modifications occur. Since the expanded ccyy1 is needed, the expanded ccyy2 is also needed for the initial assignment. As described in the previous section, the two expanded date data items, ccyy3 and ccyy4, need to be used in the UNTIL clause.
Line 5 The varied date data item, ccyy1, needs to be contracted back after being varied, in case the varied value is used in the performed code.
Lines 11, 12 and 13 The date data items might have been modified in the performed code since the PERFORM statement header. In case they have, they need re-expanding, ready for the next variation and the next comparison in line 4.
Line 15 In theory, the varied date data item, ccyy1, needs to be contracted back after dropping out of the PERFORM loop, since the last action in the PERFORM loop was to vary it. In practice, this needs to happen only if the unexpanded version of the date data item, yy1 is used subsequently.
How to fix:

SmartFix automatically generates a fix that:

  1. Expands the date data items before the PERFORM statement header. See lines 1, 2 and 3 in the fix above.

  2. Changes the PERFORM statement header to use the expanded version of the date data items. See line 4 in the fix above.

  3. Contracts the varied date data item, ccyy1 immediately after the PERFORM statement header. See line 5 in the fix above.

You need to manually edit the code to:

12.4.3 PERFORM VARYING ... Until the Varied Item Meets a Condition

Problem:

In a PERFORM VARYING ... statement, an operand, yy, is varied until it meets the condition in the UNTIL clause.

    perform varying yy1 from yy2 by 1 until yy1 > yy3
        . . . performed code . . .
    end-perform

The varied operand, yy1, might be used during the performed code and it might be modified before it is varied and tested again. An up-to-date version of this operand needs to be available to the condition every time it is tested.

Find:

  1. At the worksheet, click Display Filters.
  2. Click Defaults.
  3. In Statement, specify PERFORM*.
  4. Click OK.
Fix:
1     expand yy2 into ccyy2    *> ready for assignment in line 3
2     expand yy3 into ccyy3    *> ready for comparing in line 3
3     perform varying ccyy1 from ccyy2 by 1 until ccyy1 > ccyy3
4         contract ccyy1 into yy1    *> since ccyy1 has changed
          . . . performed code . . .
11        expand yy1 into ccyy1      *> in case yy1 has changed
12        expand yy3 into ccyy3      *> in case yy3 has changed
13    end-perform 
14    contract ccyy1 into yy1        *> since ccyy1 has changed
Line 1 In theory, this date data item, yy2 does not need expanding. However, for practical purposes it does, because it used to assign an expanded date to the date data item ccyy1 in line 3. Consequently, the date data item, ccyy1, does not need expanding initially, since it is assigned its value in line 3 from ccyy2.
Line 2 The other date data item to be compared, ccyy3, needs expanding ready for the comparison in the until clause on line 3.
Line 3 Although an expanded ccyy1 is not needed for the assignment in the first execution of the PERFORM statement, it is needed in subsequent executions where a modification occurs. Since the expanded ccyy1 is needed, the expanded ccyy2 is also needed for the initial assignment. As described in the previous section, the PERFORM statement needs to use the expanded versions of the two compared date data items, ccyy1 and ccyy3, in its UNTIL clause.
Line 4 The varied date data item, ccyy1 needs to be contracted back after being varied, in case the varied value is used in the performed code.
Lines 11 and 12 The date data items might have been modified in the performed code since the PERFORM statement header. In case they have, they need re-expanding, ready for the next variation and the next comparison in line 3. The date data item, ccyy2, that was used for the initial assignment is not used in the PERFORM statement again and so does not need re-expanding.
Line 14 In theory, the varied date data item, ccyy1, needs to be contracted back after dropping out of the PERFORM loop, since the last action in the PERFORM loop was to vary it. In practice, this needs to happen only if the unexpanded version of the date data item, yy1 is used subsequently.
How to fix:

SmartFix automatically generates a fix that:

  1. Expands the date data items before the PERFORM statement header. See lines 1 and 2 in the fix above.

  2. Changes the PERFORM statement header to use the expanded version of the date data items. See line 3 in the fix above.

  3. Contracts the varied date data item, ccyy1 immediately after the PERFORM statement header. See line 4 in the fix above.

You need to manually edit the code to:

12.4.4 PERFORM WITH TEST AFTER

Problem:

When using the WITH TEST AFTER clause, the condition is tested after the PERFORM code has been executed, and so affects which operands need to be expanded when.

    perform with test after varying yy1 from yy2 by 1 
                      until yy1 > yy3 
        . . . performed code . . .
    end-perform

In this statement, the varied operand, yy1, is not varied until the end of the performed code. Since it is possible that yy1 was modified during the performed code and it needs expanding at the end of the performed code, just before it is varied and tested.

Find:

  1. At the worksheet, click Display Filters.
  2. Click Defaults.
  3. In Statement, specify PERFORM*.
  4. Click OK.
Fix:
1     expand yy2 into ccyy2     *> ready for assigning in line 2 
2     perform test after varying ccyy1 from ccyy2 by 1
                                  until ccyy1 > ccyy3
3         contract ccyy1 into yy1   *> because ccyy1 has changed
          . . . performed code . . .
11        expand yy1 into ccyy1     *> in case yy1 has changed
12        expand yy3 into ccyy3     *> in case yy3 has changed
13    end-perform 
Line 1 The date data item ccyy2 needs expanding ready for the initial assignment.
Lines 11 and 12 These date data items ccyy1 and ccyy3 need expanding ready for the test at the end of the performed code. Note that they did not expanding before the PERFORM statement header.
How to fix:

SmartFix automatically generates a fix that:

  1. Expands the date data item, ccyy2, ready for assigning to ccyy1 in the PERFORM statement header. See line 1 in the fix above.

  2. Changes the PERFORM statement header to use the expanded version of the date data items. See line 2 in the fix above.

  3. Contracts the varied date data item, ccyy1 immediately after the PERFORM statement header. See line 3 in the fix above.

You need to manually edit the code to:

When the PERFORM loop finishes, no action is needed, since the test is done without varying any expanded operands. The expanded and contracted versions of all the operands are in step.

12.4.5 PERFORM Out-of-Line-Procedure

Problem:

In this statement an out-of-line routine is performed.

    perform routine varying yy1 from yy2 by 1 until yy1 > yy3 

The operands need attention every time through PERFORM loop, and yet you cannot apparently fix them without changing the performed routine itself.

Find:

  1. At the worksheet, click Display Filters.
  2. Click Defaults.
  3. In Statement, specify PERFORM*.
  4. Click OK.
Fix:
1     expand yy2 into ccyy2     *> ready to assign in line 3
2     expand yy3 into ccyy3     *> ready to compare in line 3
3     perform varying ccyy1 from ccyy2 by 1 until ccyy1 > ccyy3
4        contract ccyy1 into yy1
         perform routine
11       expand yy1 into ccyy1  *> ready to compare in line 3
12       expand yy3 into ccyy3  *> ready to compare in line 3
13    end-perform 
14    contract ccyy1 into yy1 
Line 1 In theory this date data item, yy2 does not need expanding. However, for practical purposes it does, because it used to assign an expanded date to the date data item ccyy1 in line 3. Consequently, the date data item, ccyy1, does not need expanding initially, since it is assigned its value in line 3 from ccyy2.
Line 2 The date data item, ccyy3, needs expanding ready for the comparison in the until clause on line 3.
Line 3 Although an expanded ccyy1 is not needed for the assignment in the first execution of the PERFORM statement, it is needed in subsequent executions where a modification occurs. Since the expanded ccyy1 is needed, the expanded ccyy2 is also needed for the initial assignment. As described in the previous section, the PERFORM statement needs to use the expanded versions of the two compared date data items, ccyy1 and ccyy3, in its UNTIL clause.
Line 5 The varied date data item, ccyy1 needs to be contracted back after being varied, in case the varied value is used in the performed code.
Lines 11 and 12 The date data items might have been modified in the performed code. In case they have, they need re-expanding, ready for the next variation and the next comparison in line 3. The date data item, ccyy2, which was used for the initial assignment, is not used in the PERFORM statement again and so does not need re-expanding.
Line 14 In theory, the varied date data item, ccyy1, needs to be contracted back after dropping out of the PERFORM loop, since the last action in the PERFORM loop was to vary it. In practice, this needs to happen only if the unexpanded version of the date data item, yy1 is used subsequently.
How to fix:

To avoid changing the performed routine, SmartFix adds an in-line PERFORM to test the condition and retains the out-of-line PERFORM without a condition. All the necessary expansions and contractions are done within the new in-line performed code, either before it is called or on return from it.

SmartFix automatically generates a fix that:

  1. Expands the date data items before the PERFORM statement header, in the same way as for an in-line PERFORM VARYING. See lines 1 and 2 in the fix above.

  2. Adds an in-line PERFORM statement that uses the expanded version of the date data items. See line 3 in the fix above.

  3. Contracts the varied date data item, ccyy1 immediately after the PERFORM statement header. See line 4 in the fix above.

  4. Changes the original PERFORM statement to just perform the out-of-line routine without any condition test. See line 5 in the fix above.

  5. Expands the date data items immediately after the out-of-line PERFORM section. If the PERFORM section code does not modify all the date data items, you need expand only the ones that are modified. See lines 11 and 12 in the fix above.

You need to manually edit the code to:

12.4.6 EXIT PERFORM and GOTO

Exiting from performed code in the middle does not cause a problem. You can exit using:

12.4.7 Summary of Fixes Needed for PERFORM Variants


Until


Test after until


Varying until


Test after varying


Before PERFORM statement:

Expand operands in FROM and BY

-

-

y

y

Expand operands compared in UNTIL

y

-

y

-

After PERFORM statement:

Contract the varied operand

-

-

y

y

After performed code:

Expand varied operand, if changed

-

-

y

y

Expand operands compared in UNTIL, if changed

y

y

y

y

After END-PERFORM statement:

Contract the varied operand

-

y

-

12.5 EVALUATE Statements

Problem:

EVALUATE statements comprise comparisons and potentially arithmetic expressions, both of which can cause problems at the century boundary. For example:

    Evaluate 05 - 95    *> fails. Should be 10 not -90.
    When 05 > 95        *> fails. Should be true not false. 

The following EVALUATE statement involves a conditional expression and so needs fixing:

    evaluate yy1 > yy2
        when true . . .
        when false . . .
    end-evaluate 

The following EVALUATE statement involves an arithmetic expression and so needs fixing:

    evaluate yy1 - yy2
        when tmp-1 . . . 
        when tmp-2 . . . 
    end-evaluate
Find:

  1. At the worksheet, click Display Filters.
  2. Click Defaults.
  3. In Statement, specify EVALUATE*.
  4. Click OK.
Fix:

SmartFix handles EVALUATE statement headers that contain conditional or arithmetic expressions, but not any of the WHEN clauses.

1    expand yy1 into ccyy1  
2    expand yy2 into ccyy2  
3    evaluate yy1 > yy2
         when true . . .
         when false . . .
     end-evaluate 
Lines 1 and 2 The year operands, yy1 and yy2, need expanding before the EVALUATE statement in line 3.
Line 3 The EVALUATE statement needs to use expanded versions of the year operands.
How to fix:

Use SmartFix to expand the year data items as described above to fix the EVALUATE statement header.

For other constructions of EVALUATE statements, you need to edit the WHEN clauses manually.

12.6 CALL Statements

Problem:

CALL statements do not in themselves cause a problem, but if you pass year data items as parameters to the called programs, you will need to check and fix those programs as necessary.

For example, in the following CALL statement, two year date data items are passed to the called program:

    call program using yy1 yy2 
Find:

  1. At the worksheet, click Display Filters.
  2. Click Defaults.
  3. In Statement, specify CALL*.
  4. Click OK.
Fix:

SmartFix fixes simple CALL statements only, fixing the year data items in the USING clause, but not if other phrases all included in the statement, such as BY VALUE.

1     expand yy1 into ccyy1  
2     expand yy2 into ccyy2  
3     call program using ccyy1 ccyy2 
Lines 1 and 2 The year data items, yy1 and yy2, need expanding before the CALL statement in line 3.
Line 3 The CALL statement needs to use expanded versions of the year data items.
How to fix:

Use SmartFix to handle the year data items as described above.

You also need to fix the called program to expect the expanded parameters. For example, if you are calling a COBOL program. you might need to update the PROCEDURE DIVISION USING statement in the called program and its Linkage section.

Restrictions:

SmartFix does not currently handle the following components of CALL statements:

In addition SmartFix does not provide any fixes for the called program or any data declarations for it.

12.7 Subtraction

If the operands input to the subtraction represent dates, SmartFix expands them before the operation. If the result is a date, it is contracted back after the operation.

Interestingly the result of a subtraction might be a year or the difference between some dates. Be wary of a non-date result that is stored in an operand that potentially holds a date. Similarly a date might be stored in a non-date data item.

12.7.1 Subtracting One Year from Another

Problem:

The following statement subtracts one year from another, giving the difference between them, and not a year. If the two year operands are in different centuries, the wrong result is produced. For example:

    subtract yy1 from yy2 giving difference 
                05 - 95 = - 90     *> wrong result
              2005 - 1995 = 10     *> correct result
Find:

  1. At the worksheet, click Display Filters.
  2. Click Defaults.
  3. In Statement, specify SUBTRACT*.
  4. Click OK.

Having studied the SUBTRACT statements, you need to examine statements with arithmetic expressions that might contain subtractions. To do this:

  1. At the worksheet, click Display Filters.
  2. Click Defaults.
  3. In Statement, specify * - *. You must put a space on both sides of the hyphen before the wildcard *.
  4. Click OK.
Fix:
1     expand yy1 into ccyy1   
2     expand yy2 into ccyy2   
3     subtract yy1 from yy2 giving difference 
Lines 1 and 2 The two year operands, ccyy1 and ccyy2, need expanding before the subtraction in line 3.
Line 3 The subtraction needs to use the two expanded year operands. In this situation, the result, difference is not a year and so does not need expanding or contracting in any way.
How to fix:

Use SmartFix to handle the year operands as described above, expanding them as necessary, according to their year types.

12.7.2 Subtracting a Value from a Year

Problem:

The following statement subtracts a value from a year, giving a new year. If the subtraction causes the century boundary to be crossed, the wrong result is produced:

    subtract temp from yy1 giving yy2 
                  03 - 5 = - 2     *> wrong result
                2003 - 5 = 1998    *> correct result
Find:

Find the subtractions in the same way as described in the section, Subtracting One Year from Another

Fix:
1     expand yy1 into ccyy1  
2     subtract temp from ccyy1 giving ccyy2 
3     contract ccyy2 into yy2       
Line 1 The year operand, yy1, needs expanding before the subtraction in line 2. However, the year operand, yy2, does not need expanding, since it is generated by the subtraction in line 2. The operand temp is not a date and so does not need expanding.
Line 2 The subtraction needs to use expanded year operand, ccyy1, and to store the result in the expanded operand, ccyy2.
Line 3 The result operand ccyy2 needs to be contracted ready for use in subsequent code.
How to fix:

Use SmartFix to handle the year operands as described above, expanding them as necessary, according to their year types.

12.7.3 Subtracting Giving a Year in a Nonyear Data Item

Problem:

In the following statement, the result is not a year and yet is stored in a data item that is allocated a year type. This causes an additional problem for you when fixing, because the year type allocated to the result operand is no longer appropriate after the operation.

    subtract yy1 from yy2
      05 - 95 = - 90      *> wrong result
      2005 - 1995 = 8     *> correct result
Find:

Find the subtractions in the same way as described in the section, Subtracting One Year from Another

Fix:
1     expand yy1 into ccyy1    
2     expand yy2 into ccyy2   
3     subtract ccyy1 from ccyy2  
3     contract ccyy2 into yy2       
Lines 1 and 2 The two year operands, yy1 and yy2, need expanding before the subtraction in line 3.
Line 3 The subtraction needs to use the two expanded year operands.
Line 4 The result operand ccyy2 needs to be contracted ready for use in subsequent code.
How to fix:

Use SmartFix to handle the year operands as described above, expanding them as necessary, according to their year types.

Comments:

In this situation, the result, ccyy2, is not a year and yet is stored in a operand that is allocated a year type. This potentially causes you a problem when fixing subsequent lines. SmartFix will expect to map the operand according to its year type in subsequent suspect lines, giving the wrong result.

To avoid this, you need to examine subsequent uses of the operand and when it does not contain a date, disable any automatic mapping of the operand to an expanded version. To disable operand mapping in one statement, go to the operand table in the SmartFix dialog and right-click the operand. You can then click Leave operand alone.

12.7.4 Negative Addition

Problem:

An addition might hide a subtraction, if one of the data items is negative or if a negative literal is used. This statement then has the same problems as a subtraction, and needs fixing in a similar way.

Find:

The negative additions might already be identified in the worksheet as a result of running Verify all research. In which case the negative additions are categorized as R-AddNegLtil. To find them:

  1. At the worksheet, click Display Filters.
  2. Click Defaults.
  3. Click Show items.
  4. Click Categories.
  5. Check R-AddNegLitl.
  6. Click OK twice.

If the negative additions are not categorized in the worksheet, you can run the tool, Find negative additions to do this. This tool searches the worksheet and identifies any ADD and COMPUTE statements in the worksheet that involve a negative literal or a signed data item. The tool then categorizes those statements and their data items as R-AddNegLitl.

Fix:
1     expand yy1 into ccyy1  
2     add temp to ccyy1 
3     contract ccyy1 into yy1       
Line 1 The year operand, yy1, needs expanding before the addition in line 2. The operand temp is not a date and so does not need expanding.
Line 2 The addition needs to use expanded year operand, ccyy1, in which the result is also stored.
Line 3 The result operand ccyy1 needs to be contracted ready for use in subsequent code.
How to fix:

Use SmartFix to handle the year operands as described above, expanding them as necessary, according to their year types. Regardless of whether the operands are positive or negative, the correct result will be produced.

12.8 Addition without Truncation

Addition of two-digit years does not always cause a problem. When numeric data items (such as PIC 99) are added, they are successfully truncated:

01  yy        PIC 99.       
0 1  yymmdd    PIC 9(6).     
. . .
    Add temp to yy         
*    05 + 98 = 03               (correct)

     Add temp to yymmdd   
*    050000 + 981122 = 031122   (correct)
Problem:

Addition of positive two-digit years causes a problem if the result is not truncated and is allowed to extend beyond the two digits. This can happen when the result operand can hold a three-digit result. For example:

01  yyyy      PIC 9(4).
0 1  ddmmyy    PIC 9(6).    
0 1  yy-comp   PIC 99 COMP.   
. . .
    Add temp to yyyy   
*    05 + 98 = 0103             (wrong)
*    05 + 1998 = 2003           (correct) 

     Add temp to ddmmyy
*    05 + 070998 = 071003       (wrong)
*    05 + 07091998  = 07092003  (correct)

     Add temp to yy-comp          
*    05 + 98 = 103              (wrong) 

Data items defined as COMPUTATIONAL do not hold the data as decimal digits. This means that a data item, such as PIC 99 COMP, is normally assigned one byte, which can hold values up to 255.

These additions can be a problem if the programs are compiled with the NOTRUNC Compiler directive, which prevents the results being truncated.

Find:

The additions without truncation might already be identified in the worksheet as a result of running Verify all research. In which case they are categorized as R-Add3DigitYr or R-UseNOTRUNC. To find them:

  1. At the worksheet, click Display Filters.
  2. Click Defaults.
  3. Click Show items.
  4. Click Categories.
  5. Check R-Add3DigitYr and R-UseNOTRUNC.
  6. Click OK twice.

If the additions without truncation are not categorized in the worksheet, you can run the tool, Find add to 3-digit year, to do this. This tool searches the worksheet for additions where the data item holding the result can hold more than 2 digits, and optionally binary items of 1 and 2 bytes. The tool then categorizes those statements and their data items as R-Add3DigitYr.

Alternatively, you can use Find potential NOTRUNC problems, which finds the additions involving COMP and COMP-4 data items of 2 bytes. The tool then categorizes those statements and their data items as R-UseNOTRUNC.

Fix:
1     expand yy1 into ccyy1  
2     add temp to ccyy1 
3     contract ccyy1 into yy1       
Line 1 The year operand, yy1, needs expanding before the addition in line 2. The operand temp is not a date and so does not need expanding.
Line 2 The addition needs to use expanded year operand, ccyy1, in which the result is also stored.
Line 3 The result operand ccyy1 needs to be contracted ready for use in subsequent code.
How to fix:

Use SmartFix to handle the year operands as described above, expanding them as necessary, according to their year types.

12.9 Date Truncation

Problem:

If a date data item is truncated by two or four digits, it is possible that the two digits representing the century are lost and this could cause a problem in subsequent statements that use the truncated item. For example:

     Move ccyy to yy   
*    Move 1956 to 56   (could cause a problem)

If the target is alphanumeric or a group item, the least significant two digits of the year are lost and the statement is probably not of interest. For example:

     Move ccyy to yy   
*    Move 1956 to 19   (not a problem)

Situations where the century might be lost through truncation are where a:

Find:

The date truncations might already be identified in the worksheet as a result of running Verify all research. In which case they are categorized as R-DateTrunc. To find them:

  1. At the worksheet, click Display Filters.
  2. Click Defaults.
  3. Click Show items.
  4. Click Categories.
  5. Check R-DateTrunc.
  6. Click OK twice.

If the date truncations are not categorized in the worksheet, you can run the tool, Find date truncation, to do this. This tool searches the worksheet for MOVE statements that truncate the values of the data items being moved. A value might be truncated because it is being moved to a data item of a smaller size, or because it is being moved from a data item of COMP format into one of Character or Display format. COMPUTATIONAL data items can hold values greater than implied by their COBOL PICTURE, which can lead to truncation. The tool then categorizes those statements and their data items as R-DateTrunc.

Fix:

The statements are not a problem in their own right and so do not need fixing.

12.10 Multiplication and Division

Multiplication and division are not frequently used on dates. However, multiplication can be used to multiply the years by 12 to calculate the number of months since 1900, or by 52 to calculate the weeks, and so on, and this might lead to problems

Multiplication and division do not cause a problem if the purpose is to convert a year into a different representation, since the century boundary is not crossed.

    multiply yy 10000 giving tmp-yyyyyy 
*             69 * 1000 = 690000

Division is similar to multiplication. The added danger is where the divisor is zero when it represents the two-digit form of the year 2000.

Find:

The multiplication or division statements might already be identified in the worksheet as a result of running Verify all research. In which case they are categorized as R-YYMultDiv. To find them:

  1. At the worksheet, click Display Filters.
  2. Click Defaults.
  3. Click Show items.
  4. Click Categories.
  5. Check R-YYMultDiv.
  6. Click OK twice.

If the multiplication or division statements are not categorized in the worksheet, you can run the tool, Find YY multiply, divide, which identifies year data items used in multiplication or division statements. This tool searches the worksheet for the statements involving 2-digit numeric data items in multiplication or division, which includes MULTIPLY, DIVIDE and COMPUTE statements. The tool then categorizes those statements and their data items as R-YYMultDiv

12.10.1 Division by the Year 00

Problems:

Division can cause a problem if the divisor is 00, representing the year 2000.

Find:

Find these divisions in the same way as described in the previous section.

Fix:

If the division is included in a COMPUTE statement or arithmetic expression, SmartFix applies the appropriate macros to handle any data items that have a year type. SmartFix uses the macros for the relevant year types and handles the statement as follows:

  1. Adds code to expand each input operand that has a year type, before the suspect statement.

  2. Changes the suspect statement to operate on the expanded operands.

  3. Compress or move the result back to the appropriate form.
Restriction:

If the suspect statement uses the DIVIDE verb, SmartFix does not provide a fix, or allow you to specify a fix. If you need to fix the statement, you have to edit the code manually.

12.11 Special Values in Date Handling

12.11.1 Literals 4, 12, 365

Problem:

In the following statement, the year operand, yy, is multiplied by 12 to calculate the months since 1900. If the year is in the 2000s the wrong result is produced. For example, to calculate the months for June 2005:

compute total-mm = (yy * 12) + mm 
*        66 = (05 * 12) + 6                   (wrong)
*        1266 = (05 * 12) + (100 *12) + 6     (correct) 

Unlike in subtractions, expanding the year operand does not solve the problem, since the computation produces the months since the year 0000, and not the months since 1900 as required. Also the result might be too large for the receiving data item. For example:

compute total-mm = (ccyy * 12) + mm 
*   24066 = (2005*12) + 6              (wrong, mm since 0000)
*   1266 = ((2005*12) + 6) - (1900*12) (correct, mm since 1900)
Find:

These date calculations might already be identified in the worksheet as a result of running Verify all research. In which case they are categorized as R-UseOfLiterals. To find them:

  1. At the worksheet, click Display Filters.
  2. Click Defaults.
  3. Click Show items.
  4. Click Categories.
  5. Check R-UseOfLiterals.
  6. Click OK twice.

If the date calculations are not categorized in the worksheet, you can run the tool, Find multiply, divide by 4, 12, 365, which identifies calculations that might operate on date values, such as leap-year calculations or time-duration calculations. The tool searches the worksheet for data items initialized to or used with the values 4, 12, 365 or 366 and then finds any statements involving those data items in multiplication or division, which includes MULTIPLY, DIVIDE and COMPUTE statements. The tool then categorizes those statements and their data items as R-UseOfLiterals

Fix:
1     expand yy1 into ccyy1  
2     subtract 1900 from ccyy1 
3     compute total-mm = (ccyy1 * 12) + mm 
Line 1 The year operand, yy1, needs expanding before the computation in line 3. The operand mm is not a year and so does not need expanding.
Line 2 The computation in line 3 is expecting the years since 1900, not since the year 0000, so 1900 needs to be subtracted from the expanded year operand, ccyy1. Although you can subtract an equivalent value after the computation, there is a danger that the result operand total-mm is not large enough, so it is safer to subtract before the computation in line 3.
Line 3 The COMPUTE statement needs to use expanded year operand, ccyy1, which now hold the years since 1900.
How to fix:

There are broadly two places where you can fix this problem. You can either fix the statements where the month value is used in a comparison, subtraction or addition. This is the usual windowing approach. However, you can fix the month value where it is calculated, where the multiplication occurs, which can be simpler and incur less change to the program.

To fix the statement where the month operand is calculated:

  1. Using SmartFix, expand the year operand, yy1, using the appropriate macro for that operand's year type. See line 1 in the fix above.

  2. In SmartFix, add a line before the COMPUTE statement, by editing the fix in the New Code tab. The new line needs to subtract 1900 from the expanded year operand, yy1. See line 2 in the fix above.

  3. Using SmartFix, change the COMPUTE statement to use the expanded operand that represents the years since 1900. See line 3 in the fix above.

To generate fixes for the statements that operate on the month operand:

  1. Create a date type, using Edit Year Type, and write the corresponding macros to handle data items that hold the months since 1900.

  2. Allocate the new date type to the total months operand, so that SmartFix will apply the macros for that date type whenever that operand is used.

  3. In the statement where the total months are calculated, do not expand the year operand or the result operand. To do this, you need to disable data item mapping for this statement. Go to the operand table in the SmartFix dialog and right-click the data item. You can then click Leave operand alone.

    This means the result does not represent the months since 1900 as originally intended.

Restriction:

If the suspect statement uses the MULTIPLY verb, SmartFix does not provide a fix, or allow you to specify a fix. If you need to fix the statement, you have to edit the code manually.

12.11.2 Literals 19 and 20

Problem:

Literals representing the century or years in some form or another can cause problems. For example specific literals representing the century, like 19 and 1900, might need fixing.

    add 1900 yy giving ccyy   
*        1900 + 03 = 1903          (wrong) 
*        2000 + 03 = 2003          (correct)

The expansion that SmartFix generates does not take account of literals that represent years or centuries. SmartFix expands the year operands correctly and then proceeds to add 1900 as well. For example:

    add 1900 ccyy-1 giving ccyy-2
*        1900 + 1903 = 3803          (wrong) 
*        1900 + 2003 = 3903          (wrong)
Find:

These embedded centuries might already be identified in the worksheet as a result of running Verify all research. In which case they are categorized as R-19/20Litl. To find them:

  1. At the worksheet, click Display Filters.
  2. Click Defaults.
  3. Click Show items.
  4. Click Categories.
  5. Check R-19/20Litl.
  6. Click OK twice.

If these embedded centuries are not categorized in the worksheet, you can run the tool, Find embedded century literals, which finds literal strings that might have a century value embedded in them, such as "July 24, 1998". This tool searches the worksheet for data items initialized to the values "* 19" and "* 20", that is 19 or 20 preceded by a space. The tools also searches for the statements that use those strings. The tool then categorizes those statements and their data items as R-19/20Litl

Fix:
1     expand yy1 into ccyy1  
2     move ccyy1 into ccyy2   
Line 1 The year operand, yy1, needs expanding, as intended in the original statement.
Line 2 The expanded year operand ccyy1 needs moving into the result operand, ccyy2, as intended in the original statement.
How to fix:

  1. Use SmartFix to expand the year operand, according to its year type, before the statement.

  2. In SmartFix, edit the code in the New Code tab to replace the original ADD statement with a MOVE statement to move the result into the required data item, ccyy2.

12.11.3 Sentinels

Problem:

Sentinel processing is the process where a date data item is used to hold a non-date value to flag some condition. Although this is not a problem in its own right, if the data item is fixed assuming that it holds a date, a problem might occur.

Find:

These sentinels might already be identified in the worksheet as a result of running Verify all research. In which case they are categorized as R-SentinelValue. To find them:

  1. At the worksheet, click Display Filters.
  2. Click Defaults.
  3. Click Show items.
  4. Click Categories.
  5. Check R-SentinelValue.
  6. Click OK twice.

If these sentinels are not categorized in the worksheet, you can run the tool, Find sentinel values: 000000 999999, which searches the worksheet for data items that might contain a value indicating a special condition, such as start or end-of-file, rather than containing a legitimate date value. The tool then categorizes those data items and their containing statements as R-SentinelValue

12.11.4 Complements

Problem:

Date data items might contain values in complement form. Typically, these fields are used to order date-values for SORT statements or in indexed file keys. The year 2000 fix might have to be adjusted to handle these values correctly.

Find:

These date values in complement form might already be identified in the worksheet as a result of running Verify all research. In which case they are categorized as R-1Complement, R-2Complement and so on. To find them:

  1. At the worksheet, click Display Filters.
  2. Click Defaults.
  3. Click Show items.
  4. Click Categories.
  5. Check R-1Complement, R-2Complement and so on.
  6. Click OK twice.

If these date values in complement form are not categorized in the worksheet, you can run the tool, Find 1s complement, Find 2s complement and so on, which search for data items that might contain date values in complement form. The Find 1s complement tool finds binary data items (COMP or COMP-4) that are initialized with high-values or hexadecimal FF and that are used in SUBTRACT statements. The tool then categorizes those statements and their data items as R-1Complement

12.12 Group Items

12.12.1 Implicit Century

Problem:

A date field that holds the century is often redefined with a subfield that omits the century. The date is set in the subfield with the assumption that the century is constant and is implicitly set.

There are two typical cases, one in which an 8-digit date of the form CCYYMMDD has a 6-digit subfield that omits the century and the other in which a 7-digit date of the form CCYYDDD has a 5-digit subfield that omits the century. In both cases, a MOVE statement that sets the subfield might yield the wrong date because the century is not adjusted.

Find:

These MOVEs to subfields might already be identified in the worksheet as a result of running Verify all research. In which case they have a category such as R-5-7Digit. To find them:

  1. At the worksheet, click Display Filters.
  2. Click Defaults.
  3. Click Show items.
  4. Click Categories.
  5. Check R-5-7Digit.
  6. Click OK twice.

If these MOVEs to subfields are not categorized in the worksheet, you can run a tool such as, Find 5- to 7-byte subfield (moves to window), which searches the worksheet for the MOVE statements where a 5-digit data item is moved either to a 7-digit elementary item or to a 5-digit item subordinate to a 7-digit group item. The tool then categorizes those statements and their data items as R-5-7Digit.

Similarly, use Find 4- to 6-byte subfield (moves to window) and so on to search for the MOVEs to subfields

12.12.2 Redefined Group Items

Problem:

Handling group items that contain elementary items representing the year is in principle the same as handling those elementary items. Since group items are not used in arithmetic, only comparisons offer a potential problem. When group items are compared, if the year is significant the result might be wrong.

    if yymmdd-1 >= yymmdd-2
         051228 >= 971228          wrong 
       20051228 >= 19971228        correct

There is an additional problem in that group items are treated as character items and not numeric items. This means the macros handling group items cannot perform arithmetic, such as adding the century onto the year.

Fix:

Since group items are not numeric, the macros to handle them use MOVE statements rather than arithmetic to determine the century. Consequently the year type that you allocate to a group item has macros designed for handling non-numeric items.

How to fix:

  1. Allocate a year type to the group item, using a year type designed for non-numeric items and designed with the date format of this group item.

  2. In SmartFix, whenever the group item is involved in a suspect statement, use the macros for its year type to expand the year operands using MOVE statements rather than arithmetic.
Comments:

If any subordinate items to a group item are defined as numeric non-display, such as PIC 9(4) COMPUTATIONAL, you cannot treat the group item as PIC X. In this case, you can edit the statement manually, or define a year type for group items like this and write the corresponding macros to handle them.

Example:

In this example, the two compared group items are treated as PIC X(6) even though their subordinate items are numeric (PIC 99).

01 yymmdd-1 
  03 yy-1          pic 99.
  03 mm-1          pic 99.
  03 dd-1          pic 99.
0 1 yymmdd-2 
  03 yy-2          pic 99.
  03 mm-2          pic 99.
  03 dd-2          pic 99.
. . .
*    If yymmdd-1 > yymmdd-2         *> original code

 * begin fix
    move yymmdd-1 to ccyymmdd-1 of ccyymmdd-1   *> expand yymmdd-1
    if ccyy-1 of ccyymmdd-1 > 60 
       move 19 to cc1 of ccyymmdd-1 
    else 
       move 20 to cc1 of ccyymmdd-1 
    end-if 
    move yymmdd-2 to ccyymmdd-2 of ccyymmdd-2   *> expand yymmdd-2
    if ccyy-2 of ccyymmdd-2 > 60 
       move 19 to cc2 of ccyymmdd-2 
    else 
       move 20 to cc2 of ccyymmdd-2 
    end-if 
    If ccyymmdd-1 > ccyymmdd-2               *> compare group items
*  end fix 

12.13 Subscripts

Problem:

If a subscript is a year and is used for accessing a table of data, problems occur when:

Fix:

SmartFix handles arithmetic expressions in subscripts in the same way as COMPUTE statements, but does not handle negative or zero subscripts.

How to fix:

To fix zero subscripts, manually edit the code to adjust the subscript to run in sequence from 1 through 99. For example, for the window 1960-2059: for dates in the 1900s, subtract 59 from the subscript, and for dates in the 2000s, add 60 to the subscript.

Year Subscript


Array of Data


60 - 59 = 1

data

99 - 59 = 40

data

00 +60 = 60

data

59+ 60 = 99

data

12.14 Reference Modification

Problems:

Reference modified operands that hold dates have the same problems as any other date operands when involved in comparisons or arithmetic. They can be fixed in the same ways.

    move record-yy-date(8:2) to account-year

However, it is possible to use a date data item as one of the modifiers, although this is a rare construct:

    move record(yy: data) to this-year-data
    move record(start: yy) to accumulated-data

If the reference modifier is a two-digit year, the code fails for the year 2000, as neither modifier can be zero. The COBOL compiler does not fail, but the logic is wrong.

How to fix:

In a similar way to fixing subscripts, adjust the offending reference modifier to run in sequence from 1 through 99. For example, for the window 1960-2059: for dates in the 1900s, subtract 59 from the modifier, and for dates in the 2000s, add 60 to the modifier.

12.15 Constructs Using Keys

SmartFix does not address any constructs that use keys, which might be dates and whose sequence might be significant. These constructs include:


Copyright © 1999 MERANT International Limited. All rights reserved.
This document and the proprietary marks and names used herein are protected by international law.
PreviousThe Worksheet Fixing Date ProblemsNext