使用1900年前的日期在Excel电子表格中进行计算

使用1900年前的日期在Excel电子表格中进行计算,excel,vba,date,Excel,Vba,Date,Microsoft Excel不识别1900年以前的日期,网上有大量信息记录了这一点,包括问题 最好的解决办法(许多其他帖子都链接到了)似乎是在 然而,尽管该解决方案使Excel能够将1900年之前的日期识别为日期,但仍不允许在计算中使用该日期,例如,当想要计算自1900年之前日期起的年数时 我的问题是,是否可以修改ExcelUser中描述的变通方法,以允许在计算中使用结果 简单地说,例如,我想用Excel计算自1756年1月4日以来的年数——这可能吗 还是必须采取另一种解决办法?也许有一些插件

Microsoft Excel不识别1900年以前的日期,网上有大量信息记录了这一点,包括问题

最好的解决办法(许多其他帖子都链接到了)似乎是在

然而,尽管该解决方案使Excel能够将1900年之前的日期识别为日期,但仍不允许在计算中使用该日期,例如,当想要计算自1900年之前日期起的年数时

我的问题是,是否可以修改ExcelUser中描述的变通方法,以允许在计算中使用结果

简单地说,例如,我想用Excel计算自1756年1月4日以来的年数——这可能吗


还是必须采取另一种解决办法?也许有一些插件可以解决这个问题?

首先,我强烈建议对日期使用格式
yyyy-mm-dd
,因为即使您只有字符串,没有真正的数字日期,这也是可以正确排序的,并且是唯一定义明确且不能被误解的日期格式,如
02/03/2021
中没有你可以说它是
mm/dd/yyyy
还是
dd/mm/yyyy
,因为两者实际上都存在

由于旧日期不能是真正的数字日期,而只能作为字符串输入(看起来像日期),这意味着需要避免误解,否则会得到错误的结果。因此,一个不能被误解的日期格式是一个明显的优势

第二,计算“X先生出生多少年”的方法不止一种:例如,让我们将1977-05-12的生日与今天的日期进行比较。今天,她今年还没有过生日,因此她已经43岁了。但今年,她将度过
44
年(
2021-1977=44
)。因此,需要更准确地提出这个问题。要么“X先生今天几岁?”要么“X先生今年几岁”。对此的计算将有所不同

让我们开始并假设以下数据。我们已经知道,Excel不能用1900年之前的日期进行计算。您可以看到,如果我们输入1900年之前的日期,它们将被格式化为字符串(红色日期),1900年之后的日期将被格式化为数字日期(绿色日期)

图1:WERT表示
#值(很抱歉看到德语屏幕截图)

同样,在D列中,使用了公式
=DATEDIF($B2,TODAY(),“y”)
,字符串日期也无法计算。但由于VBA实际上可以处理1900年之前的日期,我们可以为此编写自己的UDF(用户定义函数)。正如我上面解释的,有两种不同的计算方法,有两种不同的函数:

  • OldDateDiff(Date1,Date2,Interval)
    称为像
    =OldDateDiff($B2,TODAY(),“yyyy”)
  • OldDateAge(Date1,Date2)
    被称为像
    =OldDateAge($B2,TODAY())
选项显式
公共函数OldDateDiff(ByVal Date1作为变量,ByVal Date2作为变量,ByVal Interval作为字符串)的长度为
Dim RetVal As Long变量,用于我们要返回的值
Dim localDate1作为日期
如果VarType(Date1)=vbDate或VarType(Date1)=vbDouble,则“检查Date1是否为数字”
localDate1=CDate(Date1)’如果是数字,则接受它
ElseIf VarType(Date1)=vbString然后“检查Date1是否为字符串
localDate1=ISO8601StringToDate(Date1)“”如果是字符串,请将其转换为数字
Else的字符串和数字都不会引发错误
RetVal=CVErr(Xlerr值)
退出功能
如果结束
Dim localDate2 As Date'与Date1相同,但与Date2相同
如果VarType(Date2)=vbDate或VarType(Date2)=vbDouble,则
localDate2=CDate(Date2)
ElseIf VarType(Date2)=vbString Then
localDate2=ISO8601StringToDate(日期2)
其他的
RetVal=CVErr(Xlerr值)
退出功能
如果结束
如果localDate1 0和localDate2 0,则“请确保两个日期都填充了值”
RetVal=DateDiff(Interval,localDate1,localDate2)'计算具有所需间隔时间的日期之间的差异,例如年的yyyy
如果结束
OldDateDiff=RetVal'返回函数结果的差异
端函数
公共函数OldDateAge(ByVal Date1作为变量,ByVal Date2作为变量)的长度
Dim RetVal As Long变量,用于我们要返回的值
Dim localDate1作为日期
如果VarType(Date1)=vbDate或VarType(Date1)=vbDouble,则“检查Date1是否为数字”
localDate1=CDate(Date1)’如果是数字,则接受它
ElseIf VarType(Date1)=vbString然后“检查Date1是否为字符串
localDate1=ISO8601StringToDate(Date1)“”如果是字符串,请将其转换为数字
Else的字符串和数字都不会引发错误
RetVal=CVErr(Xlerr值)
退出功能
如果结束
Dim localDate2 As Date'与Date1相同,但与Date2相同
如果VarType(Date2)=vbDate或VarType(Date2)=vbDouble,则
localDate2=CDate(Date2)
ElseIf VarType(Date2)=vbString Then
localDate2=ISO8601StringToDate(日期2)
其他的
RetVal=CVErr(Xlerr值)
退出功能
如果结束
如果localDate1 0和localDate2 0,则“请确保两个日期都填充了值”
RetVal=WorksheetFunction.RoundDown((localDate2-localDate1)/365,0)
'从date2中减去date1,再除以365得到年份,然后四舍五入到完整年份以表示生日。
如果结束
OldDateAge=RetVal'返回作为函数结果的年龄
端函数
'将yyyy mm dd字符串转换为数字日期
私有函数ISO8601String作为日期(ByVal ISO8601String作为字符串)
Dim ISO8601Split()作为字符串
ISO8601Split=Split(ISO8601String,“-”)通过破折号将输入yyyy mm dd拆分为一个包含3个部分的数组
ISO8601串
Option Explicit

Public Function OldDateDiff(ByVal Date1 As Variant, ByVal Date2 As Variant, ByVal Interval As String) As Long
    Dim RetVal As Long 'variable for the value we want to return
    
    Dim localDate1 As Date
    If VarType(Date1) = vbDate Or VarType(Date1) = vbDouble Then 'check if Date1 is numeric
        localDate1 = CDate(Date1) 'if numeric take it
    ElseIf VarType(Date1) = vbString Then 'check if Date1 is a string
        localDate1 = ISO8601StringToDate(Date1) 'if it is a string convert it to numeric
    Else 'neither string nor numeric throw an error
        RetVal = CVErr(xlErrValue)
        Exit Function
    End If
    
    Dim localDate2 As Date 'same as for Date1 but with Date2
    If VarType(Date2) = vbDate Or VarType(Date2) = vbDouble Then
        localDate2 = CDate(Date2)
    ElseIf VarType(Date2) = vbString Then
        localDate2 = ISO8601StringToDate(Date2)
    Else
        RetVal = CVErr(xlErrValue)
        Exit Function
    End If
    
    If localDate1 <> 0 And localDate2 <> 0 Then 'make sure both dates were filled with values
        RetVal = DateDiff(Interval, localDate1, localDate2) 'calculate the difference between dates with the desired interaval eg yyyy for years
    End If
    
    OldDateDiff = RetVal 'return the difference as result of the function
End Function

Public Function OldDateAge(ByVal Date1 As Variant, ByVal Date2 As Variant) As Long
    Dim RetVal As Long 'variable for the value we want to return
    
    Dim localDate1 As Date
    If VarType(Date1) = vbDate Or VarType(Date1) = vbDouble Then 'check if Date1 is numeric
        localDate1 = CDate(Date1) 'if numeric take it
    ElseIf VarType(Date1) = vbString Then 'check if Date1 is a string
        localDate1 = ISO8601StringToDate(Date1) 'if it is a string convert it to numeric
    Else 'neither string nor numeric throw an error
        RetVal = CVErr(xlErrValue)
        Exit Function
    End If
    
    Dim localDate2 As Date 'same as for Date1 but with Date2
    If VarType(Date2) = vbDate Or VarType(Date2) = vbDouble Then
        localDate2 = CDate(Date2)
    ElseIf VarType(Date2) = vbString Then
        localDate2 = ISO8601StringToDate(Date2)
    Else
        RetVal = CVErr(xlErrValue)
        Exit Function
    End If
    
    If localDate1 <> 0 And localDate2 <> 0 Then 'make sure both dates were filled with values
        RetVal = WorksheetFunction.RoundDown((localDate2 - localDate1) / 365, 0)
          'subtract date1 from date2 and divide by 365 to get years, then round down to full years to respect the birthday date.
    End If
    
    OldDateAge = RetVal 'return the age as result of the function
End Function


' convert yyyy-mm-dd string into numeric date
Private Function ISO8601StringToDate(ByVal ISO8601String As String) As Date
    Dim ISO8601Split() As String
    ISO8601Split = Split(ISO8601String, "-") 'split input yyyy-mm-dd by dashes into an array with 3 parts
    
    ISO8601StringToDate = DateSerial(ISO8601Split(0), ISO8601Split(1), ISO8601Split(2)) 'DateSerial returns a real numeric date
                                   '     ≙yyyy             ≙mm              ≙dd
End Function
Function Age(dt As Date)
    Age = DateDiff("yyyy", dt, Date)
End Function