
Microsoft Year 2000 Readiness Disclosure
& Resource Center |
 |
 |
 |
Preparing Office Solutions for the Year
2000 |
 |
Verifying
Leap Year Algorithms
The year
2000 is a leap year. Additionally, many custom routines to determine
leap years are not Year 2000 compliant because they only work with
two digits of the year. If your application requires logic to
determine leap years, be sure to test your routine to ensure it
works in the 20th and 21st centuries. This is a Year 2000 problem
because many developers still believe (incorrectly) that 2000 is not
a leap year. Because of this, many custom leap year algorithms will
incorrectly identify 2000 as a non-leap year.
History Lesson
The
calculation of leap years is one of the more misunderstood issues in
computer science. Before jumping into the subject, let's take a
brief look at why leap years exist at all.
The
strict definition of a year is "the interval between two successive
passages of the Sun through the vernal equinox." The vernal equinox
is the exact moment when the Sun is above the equator moving south
to north. This definition of a year is known as the "tropical year"
and is 365.24219 days in length (365 days, 5 hours, 48 minutes, and
46 seconds.)
With the
introduction of the Julian calendar in 46 BC, the number of days in
a year was rounded up to 365.25. With the Julian calendar, a simple
leap year rule was used: if the year was evenly divisible by four,
it was a leap year. Unfortunately, the difference between a tropical
year (365.24219 days) and the Julian year (365.25 days) introduced
errors that over time added up. This error resulted in a year that
was 11 minutes and 14 seconds too long, which adds up to a whole day
every 128 years.
By the
1500's, this error added up to approximately 10 days. This problem
was addressed in the Gregorian calendar instituted in 1582 by Pope
Gregory XIII. The fix was to make the determination of leap years a
bit more accurate. In the Gregorian calendar, a year is defined as
being 365.2425 days in length. This is not exactly equal to a
tropical year, but is so close that the error amounts only to about
3 days in 10,000 years. If this error is a problem for you (you are
tracking the decay of atomic particles in your Access application
for example), you may need to switch to Coordinated Universal Time
(UTC) and employ "leap seconds". The coverage of this is
unfortunately beyond the scope of this paper.
Since we
now use the Gregorian calendar, we use the rule made official by
papal decree: "Every fourth year is a leap year except for century
years that are not evenly divisible by 400." What does this mean to
you? Simply put, the Year 2000 is absolutely a leap
year! Don't let anybody tell you differently. If they do, they
don't understand how to correctly determine a leap year.
Determining Leap Years
So, if a
leap year is every fourth year except for century years that are not
evenly divisible by 400, the following algorithm correctly deduces
leap years.
If MyYear Mod
4 = 0 Then ' Is it a
century? If MyYear Mod 100 = 0
Then ' If a century, must be evenly
divisible by 400 If MyYear Mod 400
= 0 Then LeapYear =
True Else LeapYear
= False End
If Else LeapYear
=
True Endif Else LeapYear
= False End If
Code Listing 8 Pseudocode for
Determining Leap Years
Note
that using the formula tells us that 1900 is not a leap year.
However, for compatibility with incorrect historical standards in
computer software, some programs consider, such as Microsoft Excel,
consider 1900 to be a leap year. How you handle this issue is
determined by whether you want to be correct or compatible. The
following code samples show two different ways to determine leap
years.
The
first procedure uses the VBA DateSerial function to determine leap
years. This approach is widely accepted, but may cause problems
because it is relying on side effect behavior of how DateSerial is
implemented. Because we have seen that Microsoft date time logic can
change between versions, or when system-level components (such as
the OLE Automation libraries) change, this approach should not be
considered 100% reliable:
Function
IsLeapYear (intYear As Integer) As Integer '
Comments : Determines if the year is a leap year using
the ' internal
DateSerial function ' Parameters: intYear -
integer
year ' Note:
Always specify the full four digits of the
year ' or the code
cannot be considered Year 2000 compliant. '
Returns : True - year is a leap year, False
otherwise ' On Error GoTo
PROC_ERR
IsLeapYear =
Month(DateSerial(intYear, 2, 29)) =
2
PROC_EXIT: Exit
Function
PROC_ERR: MsgBox "Error: "
& Err & ". " & Error$ Resume
PROC_EXIT
End Function
Code Listing 9 Determining Leap Years
using DateSerial
A better
approach is to write your own routine that does not rely on language
or operating system components.
Function
IsLeapYear2 (intYear As Integer) As Integer '
Comments : Determines if the specified year is a leap year
without ' relying
on the DateSerial method. ' Parameters: intYear
- integer
year ' Note:
Always specify the full four digits of the
year ' or the code
cannot be considered Year 2000 compliant. '
Returns : True - year is a leap year, False
otherwise ' On Error GoTo
PROC_ERR
IsLeapYear2 =
False
If intYear Mod 4 = 0
Then If intYear Mod 100 = 0
Then If intYear Mod 400 = 0
Then IsLeapYear2 =
True End
If Else IsLeapYear2
= True End If End
If
PROC_EXIT: Exit
Function
PROC_ERR: MsgBox "Error: "
& Err & ". " & Error$ Resume
PROC_EXIT
End Function
Code Listing 10 Determining Leap Years
with Simple Math
|