[AccessD] Date Difference As Completed Years-Months-Days

A.D. Tejpal adtp at airtelmail.in
Mon Apr 5 14:14:05 CDT 2010


Hi Gustav,

    I agree. It would be preferable to let VBA's built in date logic take care of all pertinent factors (e.g. month ending dates, leap years as well as varying days in different months and different years), completely eliminating the need for imposing any external logic in this regard. This would provide an output independent of subjective interpretations or preferences across developers.

    Considering the fact that adding whole number of months to Date1 via DateAdd() function shrink fits the day part of projected date so as not to exceed the maximum available number of days in the target month, it follows that the elapsed period involving month ending dates would conform to the following pattern:

    1 - (Day part of Date1) >= (Day part of Date2)
    ------------------------------------------------
    1.1 - Positive progression (Date2 >= Date1):
    1.1.1 - 31-Jan-2003 to 28-Feb-2003 = 1 month
    1.1.2 - 31-Mar-2003 to 30-Apr-2003 = 1 month
    1.1.3 - 30-Apr-2003 to 30-Sep-2003 = 5 months

    1.2 - Negative progression (Date2 < Date1):
    1.2.1 - 31-Mar-2003 to 28-Feb-2003 = -1 month
    1.2.2 - 31-May-2003 to 30-Apr-2003 = -1 month
    1.2.3 - 30-Sep-2003 to 30-Apr-2003 = -5 months

    2 - (Day part of Date1) < (Day part of Date2)
    -----------------------------------------------
    2.1 - Positive progression (Date2 >= Date1):
    2.1.1 - 28-Feb-2003 to 31-Mar-2003 = 1 month, 3 days
                (28-Feb-2003 plus 1 month = 28-Mar-2003)
    2.1.2 - 30-Apr-2003 to 31-May-2003 = 1 month, 1 day
                (30-Apr-2003 plus 1 month = 30-May-2003)

    2.2 - Negative progression (Date2 < Date1):
    2.2.1 - 28-Feb-2003 to 31-Jan-2003 = -28 days
                (28-Feb-2003 minus 1 month would have given
                28-Jan-2003, which would be out of range - 
                so, DateDiff() applied directly)
    2.2.2 - 30-Apr-2003 to 31-Mar-2003 = -30 days
                (30-Apr-2003 minus 1 month would have given
                30-Mar-2003, which would be out of range - 
                so, DateDiff() applied directly)

    You might like to examine para 2.2 above and confirm so that the YMD function could be fine tuned accordingly.

Best wishes,
A.D. Tejpal
------------

  ----- Original Message ----- 
  From: Gustav Brock 
  To: accessd at databaseadvisors.com 
  Sent: Friday, April 02, 2010 16:35
  Subject: Re: [AccessD] Date Difference As Completed Years-Months-Days


  Hi A.D.

  You are right about the behaviour of DateAdd. In- or decrementing by one month will always return a date in the next or prior month.

  However, it doesn't take into account if the date in question is ultimo of the month. That's by design, though in quite a few cases you would say that in any case adding "one month" to ultimo of one month will return ultimo of the next month and vice versa.
  This is what my function Months do:

  <code>
  Public Function Months( _
    ByVal datDate1 As Date, _
    ByVal datDate2 As Date) _
    As Integer

  ' Returns the difference in full months 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)
  '
  ' Gustav Brock, Cactus Data ApS.
  ' 2000-12-20.

    Dim intDay1           As Integer
    Dim intDay2           As Integer
    Dim intMonths         As Integer
    Dim intDaysDiff       As Integer
    Dim intReversed       As Integer
    
    ' No special error handling.
    On Error Resume Next
    
    intMonths = DateDiff("m", datDate1, datDate2)
    If intMonths = 0 Then
      ' Both dates fall within the same month.
    Else
      intDay1 = Day(datDate1)
      intDay2 = Day(datDate2)
      If Month(datDate1) < Month(DateAdd("d", 1, datDate1)) Then
        ' Date datDate1 is ultimo.
        ' Decrease date datDate2 if day of datDate2 is higher.
        If intDay2 > intDay1 Then
          datDate2 = DateAdd("d", intDay1 - intDay2, datDate2)
          intDay2 = Day(datDate2)
        End If
      End If
      If Month(datDate2) < Month(DateAdd("d", 1, datDate2)) Then
        ' Date datDate2 is ultimo.
        ' Decrease date datDate1 if day of datDate1 is higher.
        If intDay1 > intDay2 Then
          datDate1 = DateAdd("d", intDay2 - intDay1, datDate1)
          intDay1 = Day(datDate1)
        End If
      End If
      ' Calculate day difference.
      intDaysDiff = intDay1 - intDay2
      intReversed = Sgn(intMonths)
      ' Decrease count of months by one if dates are closer than one month.
      intMonths = intMonths - (intReversed * Abs((intReversed * intDaysDiff) > 0))
    End If
    
    Months = intMonths
    
  End Function
  </code>

  One could argue that this is the method to follow. For example, consider the results of DateAdd:

  DateAdd("m", 1, #2010-01-31#) => 2010-02-28
  DateAdd("m", 1, #2010-02-28#) => 2010-03-28

  while:
  DateAdd("m", 2, #2010-01-31#) => 2010-03-31

  so adding 1 + 1 month is different from adding 2 months.

  I think the YMD count should either closely follow the rules of DateAdd or the above method which would return identical results for reversed dates. 

  /gustav


More information about the AccessD mailing list