In Microsoft Access I am using the DateDiff formula in a text box on a form to calculate a person's age. The user types the date of birth and another text box called “Age” calculates and displays the age based on that date of birth and today’s date. But for some reason the age is incorrect. Here is the formula I am using to determining age.
=DateDiff("yyyy",[txtDoB1],Date()) 'today is 2/12/2021
=DateDiff("yyyy", #5/24/1979#, #2/12/2021#) 'this has the dates manually typed in
The DateDiff formula returns 42 as the age. That is not correct. It should be 41. Why is the DateDiff formula resulting in an incorrect age? What am I doing wrong?
The following solution using DateDiff is from Microsoft. I have used it and it works well. The link is: https://learn.microsoft.com/en-us/office/vba/access/Concepts/Date-Time/calculate-age
Function Age(varBirthDate As Variant) As Integer
Dim varAge As Variant
If IsNull(varBirthDate) Then Age = 0: Exit Function
varAge = DateDiff("yyyy", varBirthDate, Now)
If Date < DateSerial(Year(Now), Month(varBirthDate), _
Day(varBirthDate)) Then
varAge = varAge - 1
End If
Age = CInt(varAge)
End Function
The DateDiff formula does not calculate the difference between years very well. If you use "yyyy" in the DateDiff formula then it only uses the year portion of the 2 dates provided in the formula to calculate the difference in years. This leads to undesirable results. In your example the DateDiff formula would take 2021 from 2/12/2021 and subtract it by 1979 from 5/24/1979. Or in other words, 2021 - 1979 = 42.
Instead try using the below formula.
=Int((Date()-[txtDoB1])/365.25) '365.25 compensates for leap years
=Int((#2/11/2021#-#5/24/1979#)/365.25)
DateDiff returns the difference in calendar years.
For calculating age correct for any dates, DateAdd must be used:
' Returns the difference in full years from DateOfBirth to current date,
' optionally to another date.
' Returns zero if AnotherDate is earlier than DateOfBirth.
'
' Calculates correctly for:
' leap years
' dates of 29. February
' date/time values with embedded time values
' any date/time value of data type Date
'
' DateAdd() is used for check for month end of February as it correctly
' returns Feb. 28th when adding a count of years to dates of Feb. 29th
' when the resulting year is a common year.
'
' 2015-11-24. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function Age( _
ByVal DateOfBirth As Date, _
Optional ByVal AnotherDate As Variant) _
As Integer
Dim ThisDate As Date
Dim Years As Integer
If IsDate(AnotherDate) Then
ThisDate = CDate(AnotherDate)
Else
ThisDate = Date
End If
' Find difference in calendar years.
Years = DateDiff("yyyy", DateOfBirth, ThisDate)
If Years > 0 Then
' Decrease by 1 if current date is earlier than birthday of current year
' using DateDiff to ignore a time portion of DateOfBirth.
If DateDiff("d", ThisDate, DateAdd("yyyy", Years, DateOfBirth)) > 0 Then
Years = Years - 1
End If
ElseIf Years < 0 Then
Years = 0
End If
Age = Years
End Function
Related
I would like to get weeknumbers in ms access according to:
https://www.kalender-365.nl/kalender-2021.html
My expression:
test: DatePart("ww",#01/01/2021#,2,2)
This returns 1 instead of week 53. What can I do to return 53?
syntax:
DatePart(datepart, date, firstdayofweek, firstweekofyear)
2 = Monday (firstdayofweek)
2 = Use the first week in the year that has at least 4 days (firstdayofyear)
You may need the matching ISO year as well:
Public Const MaxWeekValue As Integer = 53
Public Const MinWeekValue As Integer = 1
Public Const MaxMonthValue As Integer = 12
Public Const MinMonthValue As Integer = 1
' Returns the ISO 8601 week of a date.
' The related ISO year is returned by ref.
'
' 2016-01-06. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function Week( _
ByVal Date1 As Date, _
Optional ByRef IsoYear As Integer) _
As Integer
Dim Month As Integer
Dim Interval As String
Dim Result As Integer
Interval = "ww"
Month = VBA.Month(Date1)
' Initially, set the ISO year to the calendar year.
IsoYear = VBA.Year(Date1)
Result = DatePart(Interval, Date1, vbMonday, vbFirstFourDays)
If Result = MaxWeekValue Then
If DatePart(Interval, DateAdd(Interval, 1, Date1), vbMonday, vbFirstFourDays) = MinWeekValue Then
' OK. The next week is the first week of the following year.
Else
' This is really the first week of the next ISO year.
' Correct for DatePart bug.
Result = MinWeekValue
End If
End If
' Adjust year where week number belongs to next or previous year.
If Month = MinMonthValue Then
If Result >= MaxWeekValue - 1 Then
' This is an early date of January belonging to the last week of the previous ISO year.
IsoYear = IsoYear - 1
End If
ElseIf Month = MaxMonthValue Then
If Result = MinWeekValue Then
' This is a late date of December belonging to the first week of the next ISO year.
IsoYear = IsoYear + 1
End If
End If
' IsoYear is returned by reference.
Week = Result
End Function
I think i have a simple problem, i just cant figure it out. I have a table with ID, Date and Value
I want to select the NEWEST value based on criteria of week and year. Meaning i only have the year and week to find the newest value.
if you do the following
SELECT TOP 1 Value from tbl WHERE year(Date)<=year and format(date,"WW")<= weeknumber
you get a problem. because if the year is 2020 and the week is 30. then if there is a value from the 31/12/2019 it wont return it because format(date,"WW") is greater than the week.
Example: dateformat=dd/mm/yyyy
ID Date Value
1 15/01/2019 15
2 31/12/2019 18
3 15/04/2020 19
if the week is 5 and the year is 2020
the result of the sql should be 18 since that is the newest value before the week and year. But the query i wrote above returns 15, which makes sence because of the week of 31/12/2019>5 and therefore wont be returned.
But how do i do this correctly?
As this probably is ISO 8601 week numbering, the year is not the calendar year but the ISO 8601 year, which native VBA knows nothing about, thus a custom function is needed:
' First day of the week.
WeekStart = DateYearWeek(5, 2020, vbMonday)
' WeekStart -> 2020-01-27
The function is not that convoluted:
' Returns the date of Monday for the ISO 8601 week of IsoYear and Week.
' Optionally, returns the date of any other weekday of that week.
'
' 2017-05-03. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function DateYearWeek( _
ByVal IsoWeek As Integer, _
Optional ByVal IsoYear As Integer, _
Optional ByVal DayOfWeek As VbDayOfWeek = VbDayOfWeek.vbMonday) _
As Date
Dim WeekDate As Date
Dim ResultDate As Date
If IsoYear = 0 Then
IsoYear = Year(Date)
End If
' Validate parameters.
If Not IsWeekday(DayOfWeek) Then
' Don't accept invalid values for DayOfWeek.
Err.Raise DtError.dtInvalidProcedureCallOrArgument
Exit Function
End If
If Not IsWeek(IsoWeek, IsoYear) Then
' A valid week number must be passed.
Err.Raise DtError.dtInvalidProcedureCallOrArgument
Exit Function
End If
WeekDate = DateAdd(IntervalSetting(dtWeek), IsoWeek - 1, DateFirstWeekYear(IsoYear))
ResultDate = DateThisWeekPrimo(WeekDate, DayOfWeek)
DateYearWeek = ResultDate
End Function
but - as you can see - it calls some helper functions, which again call other functions, which will be too much to post here.
I can upload it somewhere, if you feel this will provide a solution for you.
There is no simple work-around. On the other hand, once held in a module, the code is simple to implement - as you can see.
SELECT MIN(DateDiff("yyyy",[Employment History].[Date of 1st Promotion],Employee.[Date of Birth])) AS MinimumPromotionAge
FROM [Employee],[Employment History]
WHERE(([Employee].[Promotion]="Yes")
AND ((Employee.EmployeeID)=[Employment History].[EmployeeID]));
I have created this query in order to find the youngest average age of promotion, but there are issues with the punctuation used. Wondering if there was any advise that could help with this problem.
You can ease the reading a bit with alias:
SELECT
MIN(DateDiff("yyyy", E.[Date of 1st Promotion], E.[Date of Birth])) AS MinimumPromotionAge
FROM
[Employee] As E,
[Employment History] As EH
WHERE
E.Promotion = "Yes"
AND
E.EmployeeID = EH.EmployeeID;
but syntax seems correct, so you must be more specific about the error.
Also, DateDiff will not return the age, only the difference in calendar years.
To calculate the age, use a function like this:
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
and, in the query:
SELECT
MIN(Years(E.[Date of Birth]), E.[Date of 1st Promotion]) AS MinimumPromotionAge
FROM
<snip>
I have a table (Service_records) that contains the following fields;
Customer ID
Year
Quarter (Q1,Q2,Q3,Q4)
Service
Cost
There is also a table (Customer_records) with the customer personal details e.g. name and DoB linked by Customer ID to the above table in the subsequent query).
I also have a table with a list of financial years (Financial_years) e.g.
2015/16
2016/17
2017/18
I have created a simple form that has a combo box that will display the financial year and then a button to open a query.
The query currently is a CrossTab query with all the above tables, it shows the Service as a Row and Quarter as Columns like
-------------Q1----Q2---Q3---Q4
Service1|
Service2|
Service3|
What I would like to do is to count the number of customer IDs, who received a service, who were 30-35 years old during that quarter (>30 on first day of the Quarter) for the chosen year, our quarters run Q1-Apr-June, Q2-July-Sep, Q3-Sep-Dec, Q4 Jan-Mar.
Can this be done?
You first need a function to correctly calculate the age in full years like this:
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.
'
' 2007-11-13. Cactus Data ApS, CPH.
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
Then create a function to calculate the start date of your quarters, for example:
Public Function CalendarQuarterStart( _
ByVal FinancialYear As String, _
ByVal FinancialQuarter As String) _
As Date
Dim CalendarYear As Integer
Dim CalendarMonth As Integer
Dim DateStart As Date
CalendarYear = Val(FinancialYear) ' "2015/16"
CalendarMonth = 1 + 3 * Right(FinancialQuarter, 1) ' "Q3"
DateStart = DateSerial(CalendarYear, CalendarMonth, 1)
CalendarQuarterStart = DateStart
End Function
Thus, in your query:
Age: Years([DateOfBirth], CalendarQuarterStart([FinancialYear],[FinancialQuarter]))
How can I find the age of a person from a query on a given date from the date of birth.
I want to run a query that will return the age of everyone in a table, on any date of the following year calculated from their date of birth.
I want to return the age in years they will be, say on the 01/09(September) of the next year.
Todays date is 02/09/2015
If the date of birth is 09/10/2006 the answer is 9
If the date of birth is 28/01/2006 the answer is 10
Any ideas?? Anyone?
UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(date_in_table) gives you the difference in seconds. Now just convert to years.
You can use a Expression in the Control source of a textbox on a form
Current Date: 01/01/2015
Table1:
|Birth_Date |
|01/01/1995 | = 20
|01/01/1994 | = 21
Expression:
=DateDiff("yyyy",[BirthDate],Date())
The age will update every time you open the form
or
VBA(will need a button)
Sub Bottun1_Click()
Me.MyTextBox = DateDiff("yyyy", Me.BirthDate, Date)
End Sub
DateDiff only returns the difference in calendar years.
For a true age as of today, use a function like this:
Public Function AgeSimple( _
ByVal datDateOfBirth As Date) _
As Integer
' Returns the difference in full years from datDateOfBirth to current date.
'
' Calculates correctly for:
' leap years
' dates of 29. February
' date/time values with embedded time values
'
' 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.
' After an idea of Markus G. Fischer.
'
' 2007-06-26. Cactus Data ApS, CPH.
Dim datToday As Date
Dim intAge As Integer
Dim intYears As Integer
datToday = Date
' Find difference in calendar years.
intYears = DateDiff("yyyy", datDateOfBirth, datToday)
If intYears > 0 Then
' Decrease by 1 if current date is earlier than birthday of current year
' using DateDiff to ignore a time portion of datDateOfBirth.
intAge = intYears - Abs(DateDiff("d", datToday, DateAdd("yyyy", intYears, datDateOfBirth)) > 0)
End If
AgeSimple = intAge
End Function
For any combo of dates, use this 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