Y2K Article
Home Up Photo Album Favorites

 

Home
Up

A Y2K article you should read!

By Tom Packert

Senior Programmer Anaylyst

Avanti/Case Hoyt, Inc.

"The greatest obstacle to discovery is not ignorance - it is the illusion of knowledge." Daniel J. Boorstin

Can a Pick style application have a problem with the year 2000 change over? The answer is yes! We certainly do not have the widespread problems in application code and date storage formats like other legacy systems. We are fortunate in this fact. However, we can have code segments that introduce problems with the year 2000 because of poor coding style. If the problem was only limited to the software, then the solution would be easy, but the various hardware and other operating systems that create and use the business data that is managed by your Pick style system can effect your overall Y2K readiness.

Should anyone in Pick be concerned! Yes, the Y2K is one of the best opportunities, in a long time, for Pick applications to shine. Where there is risk there is opportunity! The problem with seizing this opportunity is to be able to demonstrate that your Pick application and supporting systems are Y2K ready and that businesses should count on you to carry them through the century change. The demonstration of this capability needs to be done in the language of the Y2K consultants. Generally, the process is referred to as Inventory, Remediation and Testing. There are many books, articles and seminars on this process so I will not repeat the information here. The Pick style date handling is called "Relative Integer Displacement" (RID).

I will not make any predictions about the possible consequences of the Y2K issue on the economy. It may be great and it may be minor depending on what happens between now and late 1999. If people in critical positions, educate themselves on the issues and set about to disrupt their already busy schedules to address the issue with the proper attention, we really don’t have that much to be concerned about. A major problem, is that often management wants all of the normal operations to continue and fails to allocate sufficient resources to resolve and prevent any Y2K issues. The lack of awareness can be disastrous. Many companies will fall into this category, you need to make sure you avoid counting on them for your own business survival.

Another possibility is that to fix the applications before the year 2000 may be prohibitively expensive because of the inflationary effect of the demand and short supply of Y2K coders and project leaders. These resources will be much cheaper after about April of 2000. Perhaps it is a better business decision to hobble through Q4 of 1999 and Q1 of 2000 to pick up the advantages of less demand. Make sure you are not counting on companies that can not demonstrate their Y2K readiness and process!

Software Recipes for detecting Y2K problems in Pick code.

First, you should search for and find all occurrences of D2/, [7,2], G2/1, ‘/’,3) and "/",3) in your applications1. There is a utility at the end of this article to help with this searching. Any occurrence of a one of the potentially troubling strings format must be reviewed to make sure that the code around the D2/ or extraction is only used for display or printing. If the result of the date conversion is used in a math function of some kind then the code with the date math must be checked by hand. You are looking to make sure that the programmer does not extract the year from the formatted date with a FIELD(VAR, "/",3) statement or a text extract like YEAR=VAR[7,2] statement. If this occurs then you may have a Y2K problem in your code.

Programmers need to be instructed to use the correct conversions as a matter of style. Using the D2/ with extractions is not recommended. Use the DY, DM, and DD conversions to extract the components of the dates. This also protects the code when the date formats change between the US and European formats of 12/31/67 and 31/12/67. The DY, DM and DD conversions work irregardless of the default system date format.

INT.DATE=DATE()

YEAR=OCONV(INT.DATE,’DY’)

MONTH=OCONV(INT.DATE,’DM’)

DAY=OCONV(INT.DATE,’DD’)

The following code segment is a real example of a poorly written, Y2K problematic bit of Pick code. This code segment will fail in late 1999 when the due dates cause the 2 digit year, 99, to increment by 1 and result in something like 01/15/100 to be ICONV’d. The date 01/15/100 is not January 15th 2000! This code segment was identified with the SHOW utility and patched in less than an hour.

243: *** CALCULATE DUE DATE

244: 70*

245: DATE.INV = OCONV(OAP.INV.DATE, "D2/")

246: MM = DATE.INV[1,2] ; DD = DATE.INV[4,2] ; YY = DATE.INV[7,2]

247: TRM.DAYS = OAP.TERMS<1,2>

248: DISC = OAP.TERMS<1,1>

249: IF TRM.DAYS[1,1] = 'P' THEN

250: IF DD > CO.PROX.CUTOFF THEN

251: NMM = MM + 2

252: END ELSE

253: NMM = MM + 1

254: END

255: IF NMM > 12 THEN

256: NMM = NMM - 12

257: YY = YY + 1

258: END

259: NMM=STR('0',2-LEN(NMM)):NMM:"/":TRM.DAYS[2,2]:"/":STR("0",2-LEN(YY)):YY

260: OAP.DUE.DATE = ICONV(NMM, "D2/")

261: END ELSE

262: IF DISC[5,2] + 0 = 0 THEN

The next step after checking the application code is to review the dictionaries in the applications. Depending on the application’s dependence on dictionaries for reports and the sophistication of the dictionaries, the degree of complexity in checking the dictionaries is greatly varied. The Pick environment that is running the application will also effect the complexity of this investigation. Relatively few dictionary items perform math, much less math on dates, but there are some and you need to find these. Again, use the show utility to identify date specific dictionary items. Make sure you also check any programs that are called from dictionary items.

Once it has been determined that there are not Y2K math related problems, the next area to turn attention to is the sorting and selecting of data. Unfortunately, some applications, use fixed length formatted dates for ids and lookup functions. This can be a tricky problem to resolve, but again it is not any inherent deficiency in Pick that causes a problem, just poor coding or procedures. Things to look for are item ids that refer to years, months, days and accounting periods.

Some applications can have no Y2K problem at all, but because users create manual procedures that are dependent on dates, they can introduce problems. For example, users that create Job or Invoice numbers that start with a two digit year. While the application itself does not have a problem, some reports may not come out sorted correctly when the job numbers change to "00". Worse still is that internal math may cause the year to disappear because the year looks like leading zeroes. The ids never had leading zeroes before. Any math performed on the ids will cause the leading zeroes to disappear. I have fixed these problems by adding a smart dictionary items for sorting that look for 9s, 0s and 1s in the first digit and to change the data value to 199X, 200X or 201X so that the reports will continue to sort correctly.

"JOB.SELECT.ID" in "DICT JOB"

001: I dict item to allow jobs to sort correctly after 12/31/99

002: IF INDEX('3456789',@ID[4,1],1) THEN @ID[1,3]:'19':@ID[4,99] ELSE IF INDEX('012',@ID[4,1],1) THEN @ID[1,3]:'20':@ID[4,99] ELSE @

ID[1,3]:'??':@ID[4,99]

003:

004: JOB]SELECT]ID

005: 12R

006: S

LIST JOB JOB.SELECT.ID

JOB

SELECT

JOB...... ID..........

003940559 00319940559

003960570 00319960570

003940560 00319940560

003960571 00319960571

003940561 00319940561

The occasion of the year "00" is a first for many applications. The year interpreted as "00" can awaken bugs that have gone undetected. A comparison of a year equal to 00 will result in a true condition when compared to NULL. Again, this is not an inherent flaw in the Pick model, just a poor coding style which will reveal itself under the new set of testing circumstances. When you are identifying troubled pieces of code, then make sure to look for comparisons of two digit years to null.

The next area to review is age calculations especially where imported data is concerned. This is not just a Y2K date issue but it falls neatly into the overall education process. The Pick Style systems generally have a cutoff date that the century change is implied in. For a Unidata system this date is 12/31/29 and 1/1/30. Entering any year between 00 and 29 the system will assume you mean 2000-2029. Any date with a year between 30 and 99 will assume 1930-1999. When data entry functions and date input processing routines see 2 digit dates, it is important to know what to do with the two digit dates and be aware of the assumptions of the environment.

CENTURY DEFAULT FOR TWO DIGIT YEAR ENTRY CHANGES AT 30

Internal date for 12/31/29 = 22646

Internal date for 01/01/30 = -13878

It is common for programmers to do some strange calculations for dates to calculate ages. The result is generally the age of very old people changes to negative. All of these date problems go away as long as the programmers use four digit dates in all internal calculations with dates.

Hardware Recipes for testing PC compliance:

The first step in ensuring you have no hardware related Y2K problems is the inventory process; making a list of everything in your company that contains a microprocessor. This is a time consuming data collection and testing process. Virtually everything that contains a processor must be checked. However, if the date of the system does not effect the overall operation of the business, it can be non-compliant, but the business can be considered Y2K Ready. Make sure the hardware you have Pick installed on is Y2K compliant. You should use the simple tests below to test all servers and mission critical systems. Systems like PC based fax servers, document image servers, email servers should all be tested. The problem with non-compliant PC based systems will be that the date stamps on files and messages will effect backups and any other software that uses dates to identify versions of images and documents.

Warning: If you are testing hardware by setting dates in the future, some software protection schemes may detect the future date of and think the license has expired. You may not be able to test and you may not be able to recover by simply setting the date back. Check with your vendor!

It is fairly common knowledge now, that PC’s older than a few months will most likely have a problem with their BIOS’. But what exactly is this problem? Does it mean the PC won’t work? No! But it may cause you grief if the date of the PC and the date the PC puts on data items or files are used by other systems and applications on the network. In this case, the non-compliant PC can quietly create problems for you down the road .

I have seen non-compliant PC’s, the most common problem is just that they don’t remember the century when they reboot after crossing into 2000. They will reboot with a date of 1980 or 1984. With the PC’s I have tested, this is the most common problem. Since PC’s tend to be rebooted fairly often, this is a major issue. If the PC is old, it is probably a good idea to replace it, because patching it may be more than it is worth. If it is not old, then you might get a BIOS upgrade for it or load a TSR to patch it, talk to the manufacturer of the PC or hit their website. There are also lots of Y2K resources on the web with lots of tools for testing and patching PC’s.

Check out:

http://www.year2000.com/,

http://www.itpolicy.gsa.gov/mks/yr2000/y2khome.htm,

http://www.ibm.com/IBM/year2000/,

Test #1 – System crosses Y2K while in operation

  1. Boot in DOS mode
  2. Change Date to 12/31/99
  3. Change time to 11:59:00pm
  4. wait for more than a minute
  5. check the date/time, it should now be 1/1/2000 and something reasonable like 12:00:30am
  6. reboot the system
  7. check the time - if it does not say 1/1/2000 then you have a non-compliant BIOS

Test #2 – System is set to date after Y2K manually

  1. Boot in DOS mode
  2. Change Date to 01/01/2000
  3. check the date/time, it should now be 1/1/2000 and something reasonable like 12:00:30am
  4. reboot the system
  5. check the time - if it does not say 1/1/2000 then you have a non-compliant BIOS

Test #3 – Check for Leap year, manual setting of date

  1. Boot in DOS mode
  2. Change Date to 02/29/2000
  3. check the date/time, it should now be 2/29/2000
  4. reboot the system
  5. check the time - if it does not say 2/29/2000 then you have a non-compliant BIOS

Test #4 – Check file system sorting of files by file’s date.

  1. Boot in DOS mode
  2. Change Date to 01/01/2000
  3. create a file with COPY CON TEST3TXT enter something then CTRL-Z to end
  4. Change Date to 01/02/2000
  5. create a file with COPY CON TEST2.TXT enter something then CTRL-Z to end
  6. Change Date to 01/03/2000
  7. create a file with COPY CON TEST1.TXT enter something then CTRL-Z to end
  8. do DIR /OD to display the directory sorted by date, it should appear with TEST3, then TEST2, then
  9. TEST1 in sorted date order
  10. reboot the system
  11. create a file with COPY CON TEST4.TXT enter something then CTRL-Z to end
  12. do DIR /OD to display the directory sorted by date, it should appear with TEST3, then TEST2, then
  13. TEST1, then TEST in sorted date order

 

Some examples of Microsoft Windows issues to look for

If you are running Window 95/98 with speadsheets you should be sure to change the Windows default date format using the Control Panel and modify the Regional Settings. The short date format should be changed to m/d/yyyy from the default m/d/yy. Then, in spreadsheets, the dates will display as four digit years as the default. The default ‘date window’ for century assumptions in Excel 97 is 12/31/29 and 1/1/30, same as Unidata. This is different from the dates in Excel 95 which are 12/31/19 and 1/1/20. The internal dates in Excel are stored as the number of days since 12/31/1899. January 1st, 1900 is day 1 in Excel, except for older Mac versions of Excel that use a different starting date. Dates may quietly change when switching between versions of spreadsheets. Excel also, wrongly thinks that 2/29/1900 is a valid date. It is NOT! Years divisible evenly by 100 must also be divisible by 400 in order to be counted as leap years. Ironically, the m/d/yyyy format is not listed under the DATE formats list, you need to view the CUSTOM formats line in Excel to see the four digit year format. The maximum year that Excel 95 can store as a number is 2078 and minimum is 1900. Excel 97 maximum is 9999 and minimum is still 1900. After and before these dates, Excel will leave the date as a text string which will not sort correctly. The DATE(YY,MM,DD) function in Excel works differently than the input routines, it always assumes 19 even when the 2 digit year is 00 through 29. The result of =DATE(00,12,31) is 12/31/1900 not 12/31/2000 as you might think. In summary, when transferring data between spreadsheets and other programs be sure to educate your users about the need to use MM/DD/YYYY for transfers to avoid any ambiguity in dates.

External

Internal

8/3/1930

11173

8/3/1930

11173

8/3/1940

14826

8/3/1949

18113

8/3/1950

18478

8/3/1960

22131

8/3/2020

44046

8/3/2025

45872

8/3/2029

47333

2/28/1900

59

2/29/1900

60

3/1/1900

61

12/31/1899

12/31/1899

 

Other things to consider

Today, there are so many processor based devices around us, we can not really be sure what will or will not work until we test these devices. The scope of the problem is large and I highly recommend buying some books, checking out web sites and learning what other people have found out. Things like burglar alarms, fire alarms, elevator systems, automatic timers for doors and doors all need to be tested. The process of inventory, remediation and testing is well developed and documented now. Managers just need to allocate the resources to check these things before it is too late. I would hate to find out that the elevator system on my 20 story office building failed and everyone had to walk up 20 flights of stairs for months until the repairman arrived with a software patch. There are many issues outside of your company’s walls that will effect you. Everyone needs to understand where the effects of Y2K will hurt them most and work to minimize this. Unfortunately, the legal system is getting geared up to ‘help’ us all resolve our issues to the tune of billions and trillions. Some estimates put the legal bill as high as 3 trillion dollars. I can not see how three trillion in legal fees can possibly help anyone but the lawyers, so I guess it really is up to us to do our best to prevent the problems before they occur.

SHOW
* PROGRAM: SHOW
* UTILITY PROGRAM TO SHOW LINES WHERE CERTAIN STRINGS APPEAR    IN TEXT
* COPYRIGHT Phase One Systems 1992
* WRITTEN BY: TOM PACKERT
*
JNK=@SENTENCE
*
*SYNTAX = SHOW FILENAME "STRING" (OPTIONS) – 
* EXAMPLES:
* SHOW BP "D2/"
* SHOW BP "D2/" (P
*
EQU AM TO CHAR(254)
EQU MAX.BYTES TO 32500
*
JNK = TRIM(JNK)
FILE = FIELD(JNK,' ',2)
X1 = INDEX(JNK,'"',1); X2 = INDEX(JNK,'"',2)
STRG = JNK[X1 + 1,X2-X1-1]
XX = INDEX(JNK[X2 + 1,99],'(',1) ;* "("options
IF XX THEN
 IF INDEX(JNK[X2+XX,99],'P',1) THEN TORP=1 ELSE TORP=0 ;* terminal    or printer
END ELSE
 TORP=0
END
*
OPEN '',FILE TO O.FILE ELSE STOP '201',FILE
*
IF STRG = '' THEN STOP '','NO SEARCH STRING'
*
IF SYSTEM(11) ELSE SELECT O.FILE
*
HEADING \'T' - PHASE ONE SYSTEMS - SHOW UTILITY 'LL'ITEM NAME    LINE DATA FROM LINE\
WDTH = @CRTWIDE-1; * get the width of the output
OFMT = 'L#':WDTH ;* set the format to print the lines with
DONE = 0
LOOP
 READNEXT ID ELSE DONE = 1
UNTIL DONE DO
 READ ITEM FROM O.FILE, ID THEN
 OFFSET = '' ;* used to keep line numbers accurate
 LOOP
 XX = INDEX(ITEM,STRG,1) ;* look for the string pattern
 WHILE XX DO
 LINE.NO = DCOUNT(ITEM[1,XX],AM) ;* determine the lines number    of the occurrence
 LINE = TRIM(ITEM<LINE.NO>) ;* strip leading spaces
 IF TORP THEN PRINTER ON
 PRINT (ID 'L#20 ':OFFSET + LINE.NO 'L#4 ':LINE) OFMT
 IF TORP THEN PRINTER OFF
 OFFSET = OFFSET + LINE.NO ;* we "shrink" the item for speed    so keep track of the line numbers
 XX = INDEX(ITEM,AM,LINE.NO);* determine char count for the    end of this line
 IF XX THEN
 ITEM = ITEM[XX + 1,MAX.BYTES] ;* shrink the item so we can    search for the first occurrence
 END ELSE ITEM = ''
 REPEAT
 END
REPEAT ;* get next item
Y2K.PICK.TEST
EQU UNIVERSAL.PICK.Y2K TO 11689
EQU UNIVERSAL.PICK.Y2K.DOW TO 'SAT'
EQU UNIVERSAL.PICK.FEB29 TO 11748
EQU UNIVERSAL.PICK.FEB29.DOW TO 'TUE'
EQU UNIVERSAL.PICK.MAR01.DOW TO 'WED'
EQU UNIVERSAL.PICK.MAR01 TO 11749
EQU UNIVERSAL.PICK.Y2K TO 11689
EQU UNIVERSAL.PICK.Y2K.DOW TO 'SAT'
EQU UNIVERSAL.PICK.FEB29 TO 11748
EQU UNIVERSAL.PICK.FEB29.DOW TO 'TUE'
EQU UNIVERSAL.PICK.MAR01.DOW TO 'WED'
EQU UNIVERSAL.PICK.MAR01 TO 11749
EQU UNIVERSAL.SINCE.1600 TO 145731
*
*
* PROGRAM TO TEST A SYSTEM FOR YEAR 2000 COMPLIANCE
*
PRINT 'The Date 01/01/2000 is day number ':ICONV('01/01/2000','D4/')
*
PRINT 'The Day of the week for 1/1/2000 is ':OCONV(ICONV('01/01/2000','D4/'),'DWA')
PRINT 'The internal date for 02/29/2000 is ':ICONV('02/29/2000','D4/')
PRINT 'The day of the week for 02/29/2000 is ':OCONV(ICONV('02/29/2000','D4/'),'DWA')
*
THIS.SYSTEM.Y2K=ICONV('01/01/2000','D4/')
THIS.SYSTEM.FEB29=THIS.SYSTEM.Y2K+59
*
IF ICONV('01/01/00','D2/') # UNIVERSAL.PICK.Y2K THEN
 PRINT 'Your system does not calculate the internal date correctly'
 PRINT 'Y2K failed'
END ELSE
 PRINT 'Iconv of 01/01/00 = ':UNIVERSAL.PICK.Y2K:' - OK!'
END
IF ICONV('01/01/2000','D4/') # UNIVERSAL.PICK.Y2K THEN
 PRINT 'Your system does not calculate the internal date correctly'
 PRINT 'Y2K failed'
END ELSE
 PRINT 'Iconv of 01/01/2000 = ':UNIVERSAL.PICK.Y2K:' - OK!'
END
*
IF ICONV('02/29/2000','D4/') # UNIVERSAL.PICK.FEB29 THEN
 PRINT 'Your system does not calculate the internal date correctly    for Feb 29, 2000'
 PRINT 'Y2K failed'
END ELSE
 PRINT 'Iconv of 02/29/2000 = ':UNIVERSAL.PICK.FEB29:' - OK!'
END
*
IF THIS.SYSTEM.FEB29 # UNIVERSAL.PICK.FEB29 THEN
 PRINT 'This system does not calculate Feb 29 correctly'
 PRINT 'Y2K failed'
END ELSE
 PRINT 'Feb 29 = Y2k + 59 days - OK!'
END
*
IF ICONV('12/31/2000','D4/') - ICONV('12/31/1999','D4/') # 366    THEN
 PRINT 'The systen does not calculate the right number of days    in 2000'
 PRINT 'Y2K failed'
END ELSE
 PRINT 'System calculated 366 days in 2000 - OK!'
END
*
END.DATE=ICONV('12/31/1999','D4/')
FIRST.DATE=ICONV('12/31/1600','D4/')
NUM.DAYS.TEST=END.DATE - FIRST.DATE
PRINT 'Number of days between 12/31/1999 and 1/1/1600 = ': NUM.DAYS.TEST
IF NUM.DAYS.TEST # UNIVERSAL.SINCE.1600 THEN
 PRINT 'Your system does not accurately count days since 12/31/1600'
END
PRINT 'CENTURY TESTING...'
*
CENTURIES='1600':@AM:'1700':@AM:'1800':@AM:'1900':@AM:'2000':@AM:'2100':@AM:'2200':@AM:'2300':@AM:'2400'
MAX.CENT=DCOUNT(CENTURIES,@AM)
FOR INDX.CENT=1 TO MAX.CENT
 CENTURY=CENTURIES<INDX.CENT>
 IS.LEAP.YEAR=NOT(MOD(CENTURY,400))
 IF IS.LEAP.YEAR THEN
 IF ICONV('02/29/':CENTURY,'D4/') = "" THEN
 PRINT 'You system wrongly thinks that ':CENTURY:' is NOT a    leap year!'
 END ELSE
 PRINT 'System system for leap year ':CENTURY:' passed!'
 END
 END ELSE
 IF ICONV('02/29/':CENTURY,'D4/') # "" THEN
 PRINT 'You system wrongly thinks that ':CENTURY:' is a leap    year!'
 END ELSE
 PRINT 'System system for non-leap year ':CENTURY:' passed!'
 END
 END
NEXT INDX.CENT
*
*
YEAR=0
LAST.CENTURY=OCONV(ICONV('01/01/':YEAR'R%2','D2/'),'DY')[1,2]
LOOP
 CENTURY=OCONV(ICONV('01/01/':YEAR'R%2','D2/'),'DY')[1,2]
UNTIL CENTURY # LAST.CENTURY DO
 YEAR=YEAR+1
REPEAT
*
PRINT 'CENTURY DEFAULT FOR TWO YEAR ENTRY CHANGES IN ':YEAR
PRINT 'Internal date for 12/31/':YEAR-1:' = ':ICONV('12/31/':YEAR-1,'D2/')
PRINT 'Internal date for 01/01/':YEAR:' = ':ICONV('01/01/':YEAR,'D2/')
 

1Disclaimer: I don’t mean to indicate that by following the recipes here, only, that you can ensure that you will have no Y2K problems in your systems. This is a good start and represents real world items that I have identified. I am sure there are programmers out there who are able to introduce Y2K problems that are not covered here.