Good.
I do it also similar, but for simplicity in understanding, it is sometimes better to show both ways (concerning the offset).
As far as the "AsOf" date, I do this to, but I declare both as strings and just check the values with IsDate. (I do this because all the dates that I use are stored in string variables (in the db as dates though). Alot less problems, considering the past ones, especially working internationally).
I try not to use variants if not needed. Here, it is not needed....Just needs to be written differently.
I did make a mistake and didn't pass ByVal - it is being passed by reference. Which will cause problems if you pass a string variable as the Birthdate, or pass a zero length.
Therefore, declare both as strings, and ByVal, then you can pass what you want(Dates, strings, date serial, or even numbers:
Function CalcAge(ByVal BirthDate As String, Optional ByVal AsOf As String) As Integer
If (Not IsDate(AsOf)) Then
AsOf = Date
End If
If (IsDate(BirthDate)) Then
CalcAge = DateDiff("yyyy", BirthDate, AsOf) _
+ (AsOf < DateSerial(Year(AsOf), Month(BirthDate), Day(BirthDate)))
Else
CalcAge = -1
End If
End Function
?CalcAge(DateAdd("d",-364,date))
=0
?CalcAge(DateAdd("d",-365,date))
=1