Gustav Brock
Gustav at cactus.dk
Tue Jun 26 06:03:30 CDT 2007
Hi John You could say it is limited, or to be more precise: 99.95% correct. It will fail in approximately 1 out of 2000 calculations. 1 out of 366 is a leapling of a leap year. 0 out of 365 is a leapling of a common year Thus, for a four year period, 1 out of 1461 is a leapling given an even distribution of births over a year (which it is not). Round it to 1 of 1500. For a four year period you will have four birth days. Thus leaplings will have 4 of 6000 birthdays. Of these, 3 out of 4 will be miscalculated which equals 3 of 6000 or 1 for every 2000, which equals an error rate of 0.05%. That may, of course, be acceptable depending on the purpose. But why? In most other cases you put a lot of efforts in reaching 0% errors. /gustav >>> john at winhaven.net 25-06-2007 23:40 >>> Hi Gustav, So the FMS SourceBook code I've been using is wrong! AgeCalc = Year(Now) - Year(datBirthDate) + (DateSerial(Year(Now), Month(datBirthDate), Day(datBirthDate)) > Now) Thanks, I'm replacing it with yours! John B. -----Original Message----- From: accessd-bounces at databaseadvisors.com [mailto:accessd-bounces at databaseadvisors.com] On Behalf Of Gustav Brock Sent: Saturday, June 23, 2007 12:56 PM To: accessd at databaseadvisors.com Subject: [AccessD] Age calculation Hi all As I have posted several times, most of the functions published around the web for this simple task is crap because they fail for calculations around Feb. 28./29., thus they are not suited for business use. Recently I noticed that DateAdd() correctly returns Feb. 28 when adding a count of years to dates of Feb. 29. resulting in dates of common years. Markus G. Fischer at Expert-Exchange came up with the idea of using this feature for serious age calculation, and so I did. I did a rewrite of my previous Years function as it could be simplified considerably using DateAdd and with the option to return negative ages in either of two ways. For a given datDate1, if datDate2 is decreased step wise one year from returning a positive count to returning a negative count, one or two occurrences of count zero will be returned. If booLinear is False, the sequence will be: 3, 2, 1, 0, 0, -1, -2 If booLinear is True, the sequence will be: 3, 2, 1, 0, -1, -2, -3 More explanation in the in-line comments. Here it is: Public Function Age( _ ByVal datDateOfBirth As Date, _ Optional ByVal varDate As Variant) _ As Integer ' Calculates age at today's date or at a specified date earlier or later in time. ' Uses Years() for calculating difference in years. ' ' Will return 0 for any varDate of the first year before datDateOfBirth. ' See comments for Years(). ' ' 2000-11-03. Cactus Data ApS, CPH. ' 2007-06-23. Supplemented with AgeLinear for count of negative ages offset by -1. Dim datDate As Date ' No special error handling. On Error Resume Next If IsDate(varDate) Then datDate = CDate(varDate) Else datDate = Date End If Age = Years(datDateOfBirth, datDate) End Function Public Function AgeLinear( _ ByVal datDateOfBirth As Date, _ Optional ByVal varDate As Variant) _ As Integer ' Calculates age at today's date or at a specified date earlier or later in time. ' Uses Years() for calculating difference in years. ' ' Will return -1 for any varDate of the first year before datDateOfBirth. ' See comments for Years(). ' ' 2007-06-23. Cactus Data ApS, CPH. Dim datDate As Date ' No special error handling. On Error Resume Next If IsDate(varDate) Then datDate = CDate(varDate) Else datDate = Date End If AgeLinear = Years(datDateOfBirth, datDate, True) End Function Public Function Years( _ ByVal datDate1 As Date, _ ByVal datDate2 As Date, _ Optional ByVal booLinear As Boolean) _ As Integer ' Returns the difference in full years between datDate1 and datDate2. ' ' Calculates correctly for: ' negative differences ' leap years ' dates of 29. February ' date/time values with embedded time values ' negative date/time values (prior to 1899-12-29) ' ' Optionally returns negative counts rounded down to provide a ' linear sequence of year counts. ' For a given datDate1, if datDate2 is decreased step wise one year from ' returning a positive count to returning a negative count, one or two ' occurrences of count zero will be returned. ' If booLinear is False, the sequence will be: ' 3, 2, 1, 0, 0, -1, -2 ' If booLinear is True, the sequence will be: ' 3, 2, 1, 0, -1, -2, -3 ' ' If booLinear is False, reversing datDate1 and datDate2 will return ' results of same absolute value, only the sign will change. ' This behaviour mimics that of Fix(). ' If booLinear is True, reversing datDate1 and datDate2 will return ' results where the negative count is offset by -1. ' This behaviour mimics that of Int(). ' DateAdd() is used for check for month end of February as it correctly ' returns Feb. 28. when adding a count of years to dates of Feb. 29. ' when the resulting year is a common year. ' ' 2000-11-03. Cactus Data ApS, CPH. ' 2000-12-16. Leap year correction modified to be symmetrical. ' Calculation of intDaysDiff simplified. ' Renamed from YearsDiff() to Years(). ' 2000-12-18. Introduced cbytMonthDaysMax. ' 2007-06-22. Version 2. Complete rewrite. ' Check for month end of February performed with DateAdd() ' after idea of Markus G. Fischer. Dim intDiff As Integer Dim intSign As Integer Dim intYears As Integer ' Find difference in calendar years. intYears = DateDiff("yyyy", datDate1, datDate2) ' For positive resp. negative intervals, check if the second date ' falls before, on, or after the crossing date for a full 12 months period ' while at the same time correcting for February 29. of leap years. If DateDiff("d", datDate1, datDate2) > 0 Then intSign = Sgn(DateDiff("d", DateAdd("yyyy", intYears, datDate1), datDate2)) intDiff = Abs(intSign < 0) Else intSign = Sgn(DateDiff("d", DateAdd("yyyy", -intYears, datDate2), datDate1)) If intSign <> 0 Then ' Offset negative count of years to continuous sequence if requested. intDiff = Abs(booLinear) End If intDiff = intDiff - Abs(intSign < 0) End If ' Return count of years as count of full 12 months periods. Years = intYears - intDiff End Function /gustav -- AccessD mailing list AccessD at databaseadvisors.com http://databaseadvisors.com/mailman/listinfo/accessd Website: http://www.databaseadvisors.com -- AccessD mailing list AccessD at databaseadvisors.com http://databaseadvisors.com/mailman/listinfo/accessd Website: http://www.databaseadvisors.com