【问题标题】:calculating age in years and months in Microsoft Access (2010)在 Microsoft Access (2010) 中以年和月为单位计算年龄
【发布时间】:2015-05-21 09:50:06
【问题描述】:

我有两个字段(体检日期和出生日期)。我计算了年龄((体检日期-出生日期)/365.25)。我想做的是在单独的字段中以年和月为单位计算年龄。我不确定是否可以使用代码生成器或其他方式来完成。

【问题讨论】:

  • @Fionnula,我看到必须在 Datediff 中指定间隔。因此,年龄将是年或月或其他一些。是否可以在单独的字段中有年和月(比如说 10 年和 5 个月)年和月?
  • @Fionnula,对不起,我之前没有仔细查看示例。它以年、月和日为单位进行计算。谢谢。

标签: database ms-access vba ms-access-2010


【解决方案1】:

处理更精细的细节需要多一点(就像一年计算一样):

Public Function Months( _
  ByVal datDate1 As Date, _
  ByVal datDate2 As Date, _
  Optional ByVal booLinear As Boolean) _
  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)
'
' Optionally returns negative counts rounded down to provide a
' linear sequence of month counts.
' For a given datDate1, if datDate2 is decreased stepwise one month 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 months to dates of Feb. 29.
' when the resulting year is a common year.
'
' 2010-03-30. Cactus Data ApS, CPH.

  Dim intDiff   As Integer
  Dim intSign   As Integer
  Dim intMonths As Integer

  ' Find difference in calendar months.
  intMonths = DateDiff("m", datDate1, datDate2)
  ' For positive resp. negative intervals, check if the second date
  ' falls before, on, or after the crossing date for a 1 month 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("m", intMonths, datDate1), datDate2))
    intDiff = Abs(intSign < 0)
  Else
    intSign = Sgn(DateDiff("d", DateAdd("m", -intMonths, datDate2), datDate1))
    If intSign <> 0 Then
      ' Offset negative count of months to continuous sequence if requested.
      intDiff = Abs(booLinear)
    End If
    intDiff = intDiff - Abs(intSign < 0)
  End If

  ' Return count of months as count of full 1 month periods.
  Months = intMonths - intDiff

End Function

【讨论】:

    【解决方案2】:

    虽然DateDiff() 函数似乎是计算年龄的合乎逻辑的选择,但不幸的是,它不能计算两个日期之间经过的完整年或月数。例如,假设一个婴儿于 2014 年 12 月 31 日出生,并在 48 小时后的 2015 年 1 月 2 日进行了检查。也就是说,

    DateOfBirth = DateSerial(2014, 12, 31)
    DateOfExam = DateSerial(2015, 1, 2)
    

    如果我们简单地使用DateDiff() 来计算她在考试时的“年龄”,以年和月为单位,我们会得到

    ?DateDiff("yyyy", DateOfBirth, DateOfExam)
     1 
    ?DateDiff("m", DateOfBirth, DateOfExam)
     1 
    

    因此,我们会报告婴儿 1 岁零 1 个月大,而实际上她只有 2 大。

    正确的年龄计算需要比这更复杂。以下 VBA 函数将以年和月为单位计算“年龄”,返回类似“2 年零 1 个月”的字符串:

    Public Function AgeInYearsAndMonths(StartDate As Variant, EndDate As Variant) As Variant
        Dim Date1 As Date, Date2 As Date
        Dim mm1 As Integer, dd1 As Integer, mm2 As Integer, dd2 As Integer
        Dim ageYears As Integer, ageMonths As Integer, rtn As Variant
        rtn = Null
        If Not (IsNull(StartDate) Or IsNull(EndDate)) Then
            If StartDate <= EndDate Then
                Date1 = StartDate
                Date2 = EndDate
            Else
                Date1 = EndDate
                Date2 = StartDate
            End If
            mm1 = Month(Date1)
            dd1 = Day(Date1)
            mm2 = Month(Date2)
            dd2 = Day(Date2)
            ageYears = DateDiff("yyyy", Date1, Date2)
            If (mm1 > mm2) Or (mm1 = mm2 And dd1 > dd2) Then
                ageYears = ageYears - 1
            End If
            ageMonths = DateDiff("m", Date1, Date2) Mod 12
            If dd1 > dd2 Then
                If ageMonths = 0 Then
                    ageMonths = 12
                End If
                ageMonths = ageMonths - 1
            End If
            If ageYears = 0 And ageMonths = 0 Then
                rtn = "less than 1 month"
            Else
                rtn = ageYears & " year" & IIf(ageYears = 1, "", "s") & " and " & ageMonths & " month" & IIf(ageMonths = 1, "", "s")
            End If
        End If
        AgeInYearsAndMonths = rtn
    End Function
    

    【讨论】:

    • 您错过的是考虑闰年。这是最困难的部分,但 DateAdd 会处理它。
    • 当我用 2012/02/29 测试上述代码时,它按我预期的那样工作。对于非闰年,生日在 02/29 的人在 02/28 仍然是 n 岁,在 03/01 仍然是 n+1 岁。我错过了什么?
    • 你错过了那些飞跃 - 那些在 2 月 29 日出生的 - 例如出生日期 2012-02-29 他/她将在 2015 年 2 月的最后一天,即 28 日是 3 年 0 个月.您可以找到一些参考资料,声称它将首先发生在 3 月 1 日。如果人们有这种感觉,那没问题,但大多数保险和组织都遵循这样的规则,即您的生日月份应该与您的生日月份一致。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-12
    相关资源
    最近更新 更多