home *** CD-ROM | disk | FTP | other *** search
- !FAST! !FAST! !FAST! !FAST! !FAST! !FAST! !FAST! !FAST! !FAST! !FAST! !FAST!
-
- File: FastDate.DOC
- Author: David N.Dubois
- Date: 1988.04.16
-
- CountDays is a !FAST! routine which tells how many days it has been since a
- specific date. It is written in assembly language, and conforms to the far
- call conventions of TurboPascal 4.0.
-
- It's somewhat cryptic, and filled with magic numbers, but it is fast.
-
- Here's how it works.
-
- Lines 35 .. 36 Standard procedure prologue for Turbo 4.0
-
- Lines 38 .. 40 Gets the Year. Make sure that it is positive. Let me
- explain. The procedure does not work with negative years.
- There are three reasons for this. First, I figured it was
- useless, particularly if you consider that the Gregorian
- calender has only been in effect since 1583. Secondly,
- signed arithemetic would have slowed the procedure
- slightly, and I didn't think it was worth it. Thirdly,
- there is no year 0. Year 1 A.D. was preceded by 1 B.C. So
- should 1 B.C. be represented by 0 or by -1? It's better to
- un-ask the question. When a negative, or zero, year is
- used, the function returns MaxLongInt.
-
- Line 42 Copy Year into BX. Now there are two copies, one in AX and
- one in BX.
-
- Lines 44 .. 46 Get the Month. Check to see if the month is March or
- beyond. The idea here, is that you want to count leap days
- for months after February on a leap year, or months upto
- February on the year after. Comparing the Month to 3 sets
- the carry flag if the Month is February or less. Doing an
- SBB (subtract with carry) will decrement AX if the Month is
- March or beyond. I will call this value Zeller's Year,
- since I understand that Mr. Zeller first thought of it.
- Now we have two different years. The actual year is in BX
- and Zeller's year is in AX.
-
- Line 47 Store Zeller's year for later.
-
- Lines 48 .. 49 Shifting right twice divides Zeller's year by 4. This tells
- us how many leap years have passed since the (alledged)
- year 0.
-
- Lines 51 .. 55 Now we find out how many days have been eaten up by the
- months that have passed. This uses the DaysIntoYear table
- shown on line 31. First, we set DI to the position of the
- table. Actually it is set to 2 bytes before the start of
- the table. This is because the first month, January, is
- stored as a 1 rather than 0. Recall that CL contains the
- month. Its still there after it was loaded in line 44.
- Since the table is of words, we multiply the Month by two,
- by shifting left, to find the index into the table. We
- clear CH (by XORing it with itself) so that now CX contains
- 2*Month. Adding that to the start of the table (less 2)
- gives us the actual offset of the number we want. The table
- is stored in the code segment, so we use a segment over-
- ride when looking up the number. This number is added to
- AX. So now, AX contains the number of leap days, plus the
- number of days in the preceding months of this year.
-
- Lines 57 .. 58 Now we add on the days into the month. Recall that CH is
- still cleared from line 39, so loading CL with the month is
- like load CX with the month. We add into CX this time. Now
- CX contains the sum of: the days into the year, plus all
- the leap days. AX has been freed for other use.
-
- Lines 60 .. 61 Now we ask, how many days have passed since the
- (hypothetical) year 0, if we count just the normal 365 days
- per year. Recall that BX contains the actual year that was
- placed there in line 42. Setting Ax to 365 and MULtiplying
- leaves the product in the DX:AX pair.
-
- Lines 62 .. 63 We add the value in CX to this. The ADC is necessary since
- this number will probably be larger than 16-bits.
-
- Lines 65 .. 68 Now we almost have our answer. All we have to do now is
- take into account those pesky years that are multiples of
- 100. Recall that multiples of 100 are not leap years,
- except for multiples of 400. This requires a time-consuming
- division operation, so I wanted to avoid it if possible. I
- figured that most calls on the function would have years in
- the 20th and 21st century, and since there were none of
- these strange leap years during the period 1901 .. 2099, I
- figured I could skip the division in these years, and make
- up for it somewhere else.
-
- Remember Zeller's Year? That was stored in SI on line 47.
- These lines check Zeller's Year, skipping to the end
- (Magic) if the year is in the 20th or 21st century.
- Otherwise we have to adjust for the 100's.
-
- Lines 70 .. 71 Our answer so far, stored in DX:AX is transferred to CX:DI
- while we do our division.
-
- Lines 72 .. 73 We are going to divide Zeller's Year by 100. We transfer
- the year, in SI, to the DX:AX pair. DX will always be zero.
-
- Lines 74 .. 76 Divide Zeller's Year by 100. This will give us the number
- of multiples of 100 that we have already counted as leap
- years, even though they may not be. This is stored in BX
- while we make a final adjustment.
-
- Lines 77 .. 78 By dividing that number by 4 (by shifting twice), we find
- out how many years have been multiples of 400.
-
- Lines 79 Adding 15 takes into account the fact that we are ignoring
- years in the range of 1901 .. 2099. Had we done this
- calcualtion for those years, we would have ended up
- subtracting 15, so instead we add 15 here.
-
- Line 80 .. 81 By adding the multiples of 400, and subtracting the
- multiples of 100, we have adjusted for the strange leap
- years. CWD quickly clears out DX for next operation.
-
- Line 82 .. 83 Recall that the original un-adjusted count was stored
- temporarily in CX:DI in lines 70 and 71. Now we add that
- onto the adjustment, leaving the result back in DX:AX.
-
- Line 84 Merge back into the main stream.
-
- Lines 86 .. 88 As I explained above, I didn't want to handle negative
- years. If Year is less than or equal to zero, the function
- returns MaxLongInt.
-
- Lines 90 .. 91 These lines add on a magic number. I'm going to keep the
- ORIGIN of this number secret.
-
- Lines 93 .. 94 Result of function is stored in DX:AX. These lines are the
- standard post-logue for the Pascal calling sequence.
-