Calculating Time Difference Exceeding 24 hours - ms-access

I am having an issue where I am trying to calculate the time difference in seconds and then in a report (Access reports) I will sum those seconds and format it into hh:nn:ss.
However, my calculated field that gathers the time difference between the two fields sometimes exceeds 24 hours and thus throws off the time difference.
I am using the DateDiff function --- DateDiff("s",[BeginningTime],[EndingTime])
What should I do when it comes to circumstances where the time exceeds 24 hours?
The two fields, BeginningTime and EndingTime, are stored in the AM/PM format. I don't think that should matter though.

You can use a function like this:
Public Function FormatHourMinute( _
ByVal datTime As Date, _
Optional ByVal strSeparator As String = ":") _
As String
' Returns count of days, hours and minutes of datTime
' converted to hours and minutes as a formatted string
' with an optional choice of time separator.
'
' Example:
' datTime: #10:03# + #20:01#
' returns: 30:04
'
' 2005-02-05. Cactus Data ApS, CPH.
Dim strHour As String
Dim strMinute As String
Dim strHourMinute As String
strHour = CStr(Fix(datTime) * 24 + Hour(datTime))
' Add leading zero to minute count when needed.
strMinute = Right("0" & CStr(Minute(datTime)), 2)
strHourMinute = strHour & strSeparator & strMinute
FormatHourMinute = strHourMinute
End Function
and this expression as ControlSource for your textbox:
=FormatHourMinute([EndingTime]-[BeginningTime])
However (see comments) this simple expression is only valid for dates of positive numeric value which are dates after 1899-12-30.
To cover all dates, you will need a proper method for calculating a timespan, and that can be done using this function:
' Converts a date value to a timespan value.
' Useful only for date values prior to 1899-12-30 as
' these have a negative numeric value.
'
' 2015-12-15. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function DateToTimespan( _
ByVal Value As Date) _
As Date
ConvDateToTimespan Value
DateToTimespan = Value
End Function
' Converts a date value by reference to a linear timespan value.
' Example:
'
' Date Time Timespan Date
' 19000101 0000 2 2
'
' 18991231 1800 1,75 1,75
' 18991231 1200 1,5 1,5
' 18991231 0600 1,25 1,25
' 18991231 0000 1 1
'
' 18991230 1800 0,75 0,75
' 18991230 1200 0,5 0,5
' 18991230 0600 0,25 0,25
' 18991230 0000 0 0
'
' 18991229 1800 -0,25 -1,75
' 18991229 1200 -0,5 -1,5
' 18991229 0600 -0,75 -1,25
' 18991229 0000 -1 -1
'
' 18991228 1800 -1,25 -2,75
' 18991228 1200 -1,5 -2,5
' 18991228 0600 -1,75 -2,25
' 18991228 0000 -2 -2
'
' 2015-12-15. Gustav Brock, Cactus Data ApS, CPH.
'
Public Sub ConvDateToTimespan( _
ByRef Value As Date)
Dim DatePart As Double
Dim TimePart As Double
If Value < 0 Then
' Get date (integer) part of Value shifted one day
' if a time part is present as -Int() rounds up.
DatePart = -Int(-Value)
' Retrieve and reverse time (decimal) part.
TimePart = DatePart - Value
' Assemble date and time part to return a timespan value.
Value = CDate(DatePart + TimePart)
Else
' Positive date values are identical to timespan values by design.
End If
End Sub
Then your expression will look like:
=FormatHourMinute(DateToTimespan([EndingTime])-DateToTimespan([BeginningTime]))
which for Gord's example values, #1899-12-28 01:00:00# and #1899-12-27 23:00:00#, will return 2:00.

Related

weeknumbers ms access query

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

SQL query, finding out the minimum of the data set

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>

MS Access person age at quarter start

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 based on a given date?

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

Random number using Date() in Expression Builder

I want to generate random number using Date() to format it like for example: ddmmyyyyHhNnSs
How do I achieve that? Is that even possible?
I was kinda hoping I can do it easy way by the expression builder but I seem to fail on each approach ;)
This number need to populate txtID field and it will be unique identifier for each database entry.
That's quite easy - with a twist.
Problem is that Rnd only returns a Single and the resolution of this only allows for 10000000 unique values. As you request a resolution to the second and with 86400 seconds per day, that only leaves a span of 115.74 days while the range of Date spans 3615899 days:
TotalDays = -CLng(#1/1/100#) + CLng(#12/31/9999#)
To overcome this, use Rnd twice which will result in 1E+15 possible values or 11574074074 days - way beyond what's needed:
RandomDouble = Rnd * Rnd
Now, to limit the possible values to fit into the range of data type Date, just follow the documentation:
RandomValue = (UpperValue - LowerValue) * Rnd + LowerValue
and apply the date values:
RandomDouble = (CLng(#12/31/9999#) - CLng(#1/1/100#)) * Rnd * Rnd + CLng(#1/1/100#)
This, however, will result in values containing unwanted milliseconds, thus perform the proper conversion to Date value using CDate which will round to the nearest second, and you have the final expression:
RandomDate = CDate((CLng(#12/31/9999#) - CLng(#1/1/100#)) * Rnd * Rnd + CLng(#1/1/100#))
Use the value as is if your field is of datatype Date or - if text - apply a format to this with Format(RandomDate, "yyyymmddhhnnss") and a sample output will be:
01770317032120
01390126010945
50140322081227
35290813165627
09330527072433
20560513105943
61810505124235
09381019130230
17010527033132
08310306233911
If you want numeric values, use CDec to convert (CLng will fail because of overflow):
RandomNumber = CDec(Format(RandomDate, "yyyymmddhhnnss"))
All said, I'm with #Bohemian - if you just want a unique timestamp and have less than one transaction per second, just use data type Date for your field and use Now:
TimeStamp = Now()
and apply a format to this of yyyymmddhhnnss.
However, Multiplying random numbers together alters the
probablility distribution:
Uniform Product Distribution
Thus, a better method is to create a random date, then a random time, and possibly a random count of milliseconds - I wrote above, that CDate rounds a value to the nearest second; it doesn't, only whenever Access displays a date/time with milliseconds the displayed valued is rounded to the second.
So I modified the function to take care of this:
Public Function DateRandom( _
Optional ByVal UpperDate As Date = #12/31/9999#, _
Optional ByVal LowerDate As Date = #1/1/100#, _
Optional ByVal DatePart As Boolean = True, _
Optional ByVal TimePart As Boolean = True, _
Optional ByVal MilliSecondPart As Boolean = False) _
As Date
' Generates a random date/time - optionally within the range of LowerDate and/or UpperDate.
' Optionally, return value can be set to include date and/or time and/or milliseconds.
'
' 2015-08-28. Gustav Brock, Cactus Data ApS, CPH.
' 2015-08-29. Modified for uniform distribution as suggested by Stuart McLachlan by
' combining a random date and a random time.
' 2015-08-30. Modified to return selectable and rounded value parts for
' Date, Time, and Milliseconds.
' 2015-08-31. An initial call of Randomize it included to prevent identical sequences.
Const SecondsPerDay As Long = 60& * 60& * 24&
Dim DateValue As Date
Dim TimeValue As Date
Dim MSecValue As Date
' Shuffle the start position of the sequence of Rnd.
Randomize
' If all parts are deselected, select date and time.
If Not DatePart And Not TimePart And Not MilliSecondPart = True Then
DatePart = True
TimePart = True
End If
If DatePart = True Then
' Remove time parts from UpperDate and LowerDate as well from the result value.
' Add 1 to include LowerDate as a possible return value.
DateValue = CDate(Int((Int(UpperDate) - Int(LowerDate) + 1) * Rnd) + Int(LowerDate))
End If
If TimePart = True Then
' Calculate a time value rounded to the second.
TimeValue = CDate(Int(SecondsPerDay * Rnd) / SecondsPerDay)
End If
If MilliSecondPart = True Then
' Calculate a millisecond value rounded to the millisecond.
MSecValue = CDate(Int(1000 * Rnd) / 1000 / SecondsPerDay)
End If
DateRandom = DateValue + TimeValue + MSecValue
End Function
Format now() and cast to a long:
select CLng(format(now(), 'ddmmyyyyhhnnss')) as txnId
Although this is not "random", it is unique as long as there are never more than one transaction per second (confirmed in comment above).