Solved Looking For Loop To Count Total Actual Days From 2 Dates (1 Viewer)

Ashfaque

Student
Local time
Today, 14:38
Joined
Sep 6, 2004
Messages
894
Hi,

I have 2 date fields as follows :

CExpDateOfJoining
LastWorkingDay

Example:
10/02/2017 as CExpDateOfJoining
31/05/2022 as LastWorkingDay

I m looking for a Access VBA Code loop (possibly using Do While) that will count actual days in that year

Means:

Year 2017 from 10 Feb 2017 to 31 Dec 2017 = 325 days included
Year 2018: 365 days included
Year 2019: 365 days included
Year 2020: 366 days included
Year 2021: 365 days included
January 2022–April 2022: 120 days included

So It is 1725 days from CExpDateOfJoining to LastWorkingDay, last working day is included.
Or 4 years, 8 months, 22 days including the LastWorkingDay.

TotServiceYr =4
TotServiceMonths =8
TotServiceDays =22

Thanks,
 

CJ_London

Super Moderator
Staff member
Local time
Today, 10:08
Joined
Feb 19, 2013
Messages
16,607
I come up with different figures - I make it 1906 days, not 1725

?datediff("d",#2017-02-10#,#2022-04-30#)+1
1906

and 5 years, not 4
?datediff("yyyy",#2017-02-10#,#2022-04-30#)
5

and 2 months not 8
?datediff("m",#2017-02-10#,#2022-04-30#)-(5*12)
2


If you want the number of years/months/days gets a bit more complicated
 

plog

Banishment Pending
Local time
Today, 04:08
Joined
May 11, 2011
Messages
11,645
What's so magical about a loop? There's a built in function to do just what you want:


Also, CJ's answers are correct and not yours.
 

arnelgp

..forever waiting... waiting for jellybean!
Local time
Today, 17:08
Joined
May 7, 2009
Messages
19,234
Code:
'***************** Code Start **************
Public Function Diff2Dates(interval As String, Date1 As Variant, Date2 As Variant, _
Optional ShowZero As Boolean = False) As Variant
'Author:    ? Copyright 2001 Pacific Database Pty Limited
'           Graham R Seach MCP MVP gseach@pacificdb.com.au
'           Phone: +61 2 9872 9594  Fax: +61 2 9872 9593
'           This code is freeware. Enjoy...
'           (*) Amendments suggested by Douglas J. Steele MVP
'
'Description:   This function calculates the number of years,
'               months, days, hours, minutes and seconds between
'               two dates, as elapsed time.
'
'Inputs:    Interval:   Intervals to be displayed (a string)
'           Date1:      The lower date (see below)
'           Date2:      The higher date (see below)
'           ShowZero:   Boolean to select showing zero elements
'
'Outputs:   On error: Null
'           On no error: Variant containing the number of years,
'               months, days, hours, minutes & seconds between
'               the two dates, depending on the display interval
'               selected.
'           If Date1 is greater than Date2, the result will
'               be a negative value.
'           The function compensates for the lack of any intervals
'               not listed. For example, if Interval lists "m", but
'               not "y", the function adds the value of the year
'               component to the month component.
'           If ShowZero is True, and an output element is zero, it
'               is displayed. However, if ShowZero is False or
'               omitted, no zero-value elements are displayed.
'               For example, with ShowZero = False, Interval = "ym",
'               elements = 0 & 1 respectively, the output string
'               will be "1 month" - not "0 years 1 month".

On Error GoTo Err_Diff2Dates

   Dim booCalcYears As Boolean
   Dim booCalcMonths As Boolean
   Dim booCalcDays As Boolean
   Dim booCalcHours As Boolean
   Dim booCalcMinutes As Boolean
   Dim booCalcSeconds As Boolean
   Dim booCalcWeeks As Boolean
   Dim booSwapped As Boolean
   Dim dtTemp As Date
   Dim intCounter As Integer
   Dim lngDiffYears As Long
   Dim lngDiffMonths As Long
   Dim lngDiffDays As Long
   Dim lngDiffHours As Long
   Dim lngDiffMinutes As Long
   Dim lngDiffSeconds As Long
   Dim lngDiffWeeks As Long
   Dim varTemp As Variant

   Const INTERVALS As String = "dmyhnsw"

'Check that Interval contains only valid characters
   interval = LCase$(interval)
   For intCounter = 1 To Len(interval)
      If InStr("/: ", Mid(interval, intCounter, 1)) > 0 Then
        'ignore
      Else
        If InStr(1, INTERVALS, Mid$(interval, intCounter, 1)) = 0 Then
           Exit Function
        End If
     End If
   Next intCounter

'Check that valid dates have been entered
   If IsNull(Date1) Then Exit Function
   If IsNull(Date2) Then Exit Function
   If Not (IsDate(Date1)) Then Exit Function
   If Not (IsDate(Date2)) Then Exit Function

'If necessary, swap the dates, to ensure that
'Date1 is lower than Date2
   If Date1 > Date2 Then
      dtTemp = Date1
      Date1 = Date2
      Date2 = dtTemp
      booSwapped = True
   End If

   Diff2Dates = Null
   varTemp = Null

'What intervals are supplied
   booCalcYears = (InStr(1, interval, "y") > 0)
   booCalcMonths = (InStr(1, interval, "m") > 0)
   booCalcDays = (InStr(1, interval, "d") > 0)
   booCalcHours = (InStr(1, interval, "h") > 0)
   booCalcMinutes = (InStr(1, interval, "n") > 0)
   booCalcSeconds = (InStr(1, interval, "s") > 0)
   booCalcWeeks = (InStr(1, interval, "w") > 0)

'Get the cumulative differences
   If booCalcYears Then
      lngDiffYears = Abs(DateDiff("yyyy", Date1, Date2)) - _
              IIf(Format$(Date1, "mmddhhnnss") <= Format$(Date2, "mmddhhnnss"), 0, 1)
      Date1 = DateAdd("yyyy", lngDiffYears, Date1)
   End If

   If booCalcMonths Then
      lngDiffMonths = Abs(DateDiff("m", Date1, Date2)) - _
              IIf(Format$(Date1, "ddhhnnss") <= Format$(Date2, "ddhhnnss"), 0, 1)
      Date1 = DateAdd("m", lngDiffMonths, Date1)
   End If

   If booCalcWeeks Then
      lngDiffWeeks = Abs(DateDiff("w", Date1, Date2)) - _
              IIf(Format$(Date1, "hhnnss") <= Format$(Date2, "hhnnss"), 0, 1)
      Date1 = DateAdd("ww", lngDiffWeeks, Date1)
   End If

   If booCalcDays Then
      lngDiffDays = Abs(DateDiff("d", Date1, Date2)) - _
              IIf(Format$(Date1, "hhnnss") <= Format$(Date2, "hhnnss"), 0, 1)
      Date1 = DateAdd("d", lngDiffDays, Date1)
   End If

   If booCalcHours Then
      lngDiffHours = Abs(DateDiff("h", Date1, Date2)) - _
              IIf(Format$(Date1, "nnss") <= Format$(Date2, "nnss"), 0, 1)
      Date1 = DateAdd("h", lngDiffHours, Date1)
   End If

   If booCalcMinutes Then
      lngDiffMinutes = Abs(DateDiff("n", Date1, Date2)) - _
              IIf(Format$(Date1, "ss") <= Format$(Date2, "ss"), 0, 1)
      Date1 = DateAdd("n", lngDiffMinutes, Date1)
   End If

   If booCalcSeconds Then
      lngDiffSeconds = Abs(DateDiff("s", Date1, Date2))
      Date1 = DateAdd("s", lngDiffSeconds, Date1)
   End If

   If booCalcYears And (lngDiffYears > 0 Or ShowZero) Then
      varTemp = lngDiffYears & IIf(lngDiffYears <> 1, " years", " year")
   End If

   If booCalcMonths And (lngDiffMonths > 0 Or ShowZero) Then
      If booCalcMonths Then
         varTemp = varTemp & IIf(IsNull(varTemp), Null, " ") & _
                   lngDiffMonths & IIf(lngDiffMonths <> 1, " months", " month")
      End If
   End If

   If booCalcWeeks And (lngDiffWeeks > 0 Or ShowZero) Then
      If booCalcWeeks Then
         varTemp = varTemp & IIf(IsNull(varTemp), Null, " ") & _
                   lngDiffWeeks & IIf(lngDiffWeeks <> 1, " weeks", " week")
      End If
   End If

   If booCalcDays And (lngDiffDays > 0 Or ShowZero) Then
      If booCalcDays Then
         varTemp = varTemp & IIf(IsNull(varTemp), Null, " ") & _
                   lngDiffDays & IIf(lngDiffDays <> 1, " days", " day")
      End If
   End If

   If booCalcHours And (lngDiffHours > 0 Or ShowZero) Then
      If booCalcHours Then
         varTemp = varTemp & IIf(IsNull(varTemp), Null, " ") & _
                   lngDiffHours & IIf(lngDiffHours <> 1, " hours", " hour")
      End If
   End If

   If booCalcMinutes And (lngDiffMinutes > 0 Or ShowZero) Then
      If booCalcMinutes Then
         varTemp = varTemp & IIf(IsNull(varTemp), Null, " ") & _
                   lngDiffMinutes & IIf(lngDiffMinutes <> 1, " minutes", " minute")
      End If
   End If

   If booCalcSeconds And (lngDiffSeconds > 0 Or ShowZero) Then
      If booCalcSeconds Then
         varTemp = varTemp & IIf(IsNull(varTemp), Null, " ") & _
                   lngDiffSeconds & IIf(lngDiffSeconds <> 1, " seconds", " second")
      End If
   End If

   If booSwapped Then
      varTemp = "-" & varTemp
   End If

   Diff2Dates = Trim$(varTemp)

End_Diff2Dates:
   Exit Function

Err_Diff2Dates:
   Resume End_Diff2Dates

End Function
'************** Code End *****************

test:

?Diff2Dates("ymd",#2/10/2017#,#5/31/2022#)

result:

5 years 3 months 21 days
 

Pat Hartman

Super Moderator
Staff member
Local time
Today, 05:08
Joined
Feb 19, 2002
Messages
43,263
Loops are the slowest way to do anything. Make sure you have investigated all other options first. Find the function list for vba and keep it handy for reference.

Functions (category list) | Microsoft Docs
slightly different:
Access Functions (by category) (microsoft.com)

When you need to update data, try to create an action query first. It is rare that you won't be able to use a query and are forced to use a VBA loop to update multiple records.
 

Ashfaque

Student
Local time
Today, 14:38
Joined
Sep 6, 2004
Messages
894
What's so magical about a loop? There's a built in function to do just what you want:


Also, CJ's answers are correct and not yours.
Thanks you plog for your efforts to solve the issue.

4 years, 8 months, 22 days is the correct calculated days from the period given. I am calculating End Of Service Benefit of employees. It the yrs, months and days are wrong then EOSB of will be wrong..isnt it?

Therefore, I need to count exact Years, Months and Days (all leap and non-leap year) so there shall be no financial loss of either company or employee.
 

arnelgp

..forever waiting... waiting for jellybean!
Local time
Today, 17:08
Joined
May 7, 2009
Messages
19,234
actually based on the Data at post#1, the Last day of Work is May 31, 2022 not April.
so January 2022 - May 31, 2022 is 151 days.

so the new total is 1937 days and is:

5 year(s) 3 month(s) 22 day(s)
Code:
Public Function ESB(ByVal dtStart As Date, dtEnd As Date) As String
' arnelgp
' return the End of Service Benefit
' year, month and day
Dim yr As Integer, iYr As Integer, iMo As Integer, iDy As Integer, yrEnd As Integer
yr = Year(dtStart)
yrEnd = Year(dtEnd)
If yr = yrEnd Then
    ESB = DateDiff("d", dtStart, dtEnd) + 1 & " day(s)"
    Exit Function
Else
    Do While yr < yrEnd
        If yr = Year(dtStart) Then
            iDy = iDy + DatePart("y", DateSerial(yr, 12, 31)) - DatePart("y", dtStart) + 1
        Else
            iDy = iDy + DatePart("y", DateSerial(yr, 12, 31))
        End If
        yr = yr + 1
    Loop
End If
iDy = iDy + DatePart("y", dtEnd)
iYr = iDy \ 365
iDy = iDy - (iYr * 365)
iMo = iDy \ 30
iDy = iDy - (iMo * 30)
ESB = iYr & " year(s) " & iMo & " month(s) " & iDy & " day(s)"
End Function
 
Last edited:

Ashfaque

Student
Local time
Today, 14:38
Joined
Sep 6, 2004
Messages
894
actually based on the Data at post#1, the Last day of Work is May 31, 2022 not April.
so January 2022 - May 31, 2022 is 151 days.

so the new total is 1937 days and is:

5 year(s) 3 month(s) 22 day(s)
Code:
Public Function ESB(ByVal dtStart As Date, dtEnd As Date) As String
' arnelgp
' return the End of Service Benefit
' year, month and day
Dim yr As Integer, iYr As Integer, iMo As Integer, iDy As Integer, yrEnd As Integer
yr = Year(dtStart)
yrEnd = Year(dtEnd)
If yr = Year(dtEnd) Then
    ESB = DateDiff("d", dtStart, dtEnd) + 1 & " day(s)"
    Exit Function
Else
    Do While yr < yrEnd
        If yr = Year(dtStart) Then
            iDy = iDy + DatePart("y", DateSerial(yr, 12, 31)) - DatePart("y", dtStart) + 1
        Else
            iDy = iDy + DatePart("y", DateSerial(yr, 12, 31))
        End If
        yr = yr + 1
    Loop
End If
iDy = iDy + DatePart("y", dtEnd)
iYr = iDy \ 365
iDy = iDy - (iYr * 365)
iMo = iDy \ 30
iDy = iDy - (iMo * 30)
ESB = iYr & " year(s) " & iMo & " month(s) " & iDy & " day(s)"
End Function
Thanks Arnel,

You are correct it is up to May so 151 days in 2022
Let me check your code....
 

arnelgp

..forever waiting... waiting for jellybean!
Local time
Today, 17:08
Joined
May 7, 2009
Messages
19,234
i would suggest you just use the function in post #5.
 

Ashfaque

Student
Local time
Today, 14:38
Joined
Sep 6, 2004
Messages
894
I saved your code in Std module and called under on click even of a button as follows:

Call ESB

it produced "Invalid Use of Property"
 

arnelgp

..forever waiting... waiting for jellybean!
Local time
Today, 17:08
Joined
May 7, 2009
Messages
19,234
is your database also called ESB, you need to rename the Module and/or Rename the function, like , fncESB
 

arnelgp

..forever waiting... waiting for jellybean!
Local time
Today, 17:08
Joined
May 7, 2009
Messages
19,234
delete the module and paste it again in new module and rename the function.
 

Gasman

Enthusiastic Amateur
Local time
Today, 10:08
Joined
Sep 21, 2011
Messages
14,267
I saved your code in Std module and called under on click even of a button as follows:

Call ESB

it produced "Invalid Use of Property"
It is a Function. :(
You need to pass it required parameters to get back a value which you assign to a variable?

Works fine for me, except they produce different values?
Code:
? esb(#01/15/2015#,#11/09/2021#)
6 year(s) 10 month(s) 1 day(s)
? Diff2Dates("ymd",#01/15/2015#,#11/09/2021#)
6 years 9 months 25 days

Perhaps rename the module modAnelgp and put all the code he gives you into that module?
You might need modAnelgp1 and modAnelgp2 if you want to keep them fairly small.
 
Last edited:

CJ_London

Super Moderator
Staff member
Local time
Today, 10:08
Joined
Feb 19, 2013
Messages
16,607
logic says to me

full years - 01/15/2015-01/14/2021=6
full months -from 01/15/2021-10/14/2021=9
full days - from 10/15/2021-11/09/2021=25

so Diff2Dates would be the one for me before further testing.
 

Ashfaque

Student
Local time
Today, 14:38
Joined
Sep 6, 2004
Messages
894
Arnel,

Your code supports for American date format

I tried changing module name and immidate window show me following effect with British and American date format.

?testesb(#09/10/2017#,#05/31/2022#)
4 year(s) 8 month(s) 25 day(s)

?testesb(#10/09/2017#,#31/05/2022#)
4 year(s) 7 month(s) 26 day(s)

We are using British Date format in middle east and the following website produces correct date calculations

https://www.timeanddate.com/date/durationresult.html?d1=10&m1=9&y1=2017&d2=31&m2=5&y2=2022&ti=on

With American date still 3 days diff but that it is adjustable. May be I am wrong but I think this 3 days difference occurred i.e. 1 day from 2020 as leap year and startdate and lastdate itself are not included there so 1 day from each dtStart and dtEnd. This might have counted total 3 days.

Can you set the format according to dd/mm/yyyy?

Thanks,
 
Last edited:

Minty

AWF VIP
Local time
Today, 10:08
Joined
Jul 26, 2013
Messages
10,371
All dates are processed in access using American format when using VBA written queries.

The safest route is to use yyyy-mm-dd formatting everywhere as that works no matter where you are.
Your forms will work and display the correct version for the local, your code should take those values and make them all yyyy-mm-dd
 

Gasman

Enthusiastic Amateur
Local time
Today, 10:08
Joined
Sep 21, 2011
Messages
14,267
Arnel,

Your code supports for American date format

I tried changing module name and immidate window show me following effect with British and American date format.

?testesb(#09/10/2017#,#05/31/2022#)
4 year(s) 8 month(s) 25 day(s)

?testesb(#10/09/2017#,#31/05/2022#)
4 year(s) 7 month(s) 26 day(s)

We are using British Date format in middle east and the following website produces correct date calculations

https://www.timeanddate.com/date/durationresult.html?d1=10&m1=9&y1=2017&d2=31&m2=5&y2=2022&ti=on

With American date still 3 days diff but that it is adjustable. May be I am wrong but I think this 3 days difference occurred i.e. 1 day from 2020 as leap year and startdate and lastdate itself are not included there so 1 day from each dtStart and dtEnd. This might have counted total 3 days.

Can you set the format according to dd/mm/yyyy?

Thanks,
Matters not a jot. Use mm/dd/yyyy or as Minty states yyyy-mm-dd
However if the dates are true dates, I would have thought it would not make a difference if the function expected an actual date value and not a formatted date value?
 

Ashfaque

Student
Local time
Today, 14:38
Joined
Sep 6, 2004
Messages
894
Arnel,

You code is almost close to the desired result. I want my From and To dates to pickup from forms (CExpDateOfJoining & LastworkingDay) and produce the result. To get this I just placed one text box and a new cmnd btn under which I called the function as follows: (I changed the ESB function name to TESTESB.)

Call TESTESB

It is still producing error "Invalid use of property" when I call the function thru a new command btn
 

Users who are viewing this thread

Top Bottom