当另一个单元格的值发生变化时,一个单元格中的自动日期更新(通过公式计算)
Posted
技术标签:
【中文标题】当另一个单元格的值发生变化时,一个单元格中的自动日期更新(通过公式计算)【英文标题】:Automatic date update in a cell when another cell's value changes (as calculated by a formula) 【发布时间】:2012-03-07 21:24:30 【问题描述】:我在 C2 中有一个公式,比如=A2+B2
。每当 C2 更改值(实际值,而不是公式)时,我希望在 D2 中更新当前日期和时间。
我尝试了很多 VBA 代码和技巧,但如果在 C2 中输入公式,它们都不起作用。但是如果我在 C2 中手动输入一个值,日期和时间会根据需要更新。这当然是因为输入/更改了实际值 - 可以这么说,公式保持不变。
问题: 当 C2 中的公式结果发生变化时,是否可以创建更新 D2 的 VBA 代码(或其他代码)?
如果可能,我需要为单元格 C2:C30 启用此功能(+ D2:D30 表示日期+时间)
使用 Excel 2010。
【问题讨论】:
“我已经尝试了很多 VBA 代码”小心告诉我们what you have tried? 【参考方案1】:您可以通过将 C2-Cell 的值作为输入参数的用户定义函数(VBA 宏函数)填充依赖单元格 (D2),并将当前日期作为输出返回。
将 C2 作为 D2 中 UDF 的输入参数会告诉 Excel,每次 C2 更改时(即如果为工作簿打开公式的自动计算),它都需要重新评估 D2。
编辑:
这里有一些代码:
对于 UDF:
Public Function UDF_Date(ByVal data) As Date
UDF_Date = Now()
End Function
作为 D2 中的公式:
=UDF_Date(C2)
您必须为 D2-Cell 提供日期时间格式,否则它将显示日期值的数字表示。
如果您在 D2 公式中保持 C2 引用是相对的,则可以通过拖动将公式扩展至所需范围。
注意: 这可能仍然不是理想的解决方案,因为每次 Excel 重新计算工作簿时,D2 中的日期都会重置为当前值。 为了使 D2 仅反映 C2 上次更改的时间,必须对 C2 的过去值进行某种跟踪。 例如,这可以在 UDF 中实现,方法是在输入参数的值旁边还提供地址,将输入参数存储在隐藏表中,并在每次调用 UDF 时将它们与之前的值进行比较。
附录:
这是一个 UDF 的示例实现,它跟踪单元格值的变化并返回检测到最后一次变化的日期时间。 使用时请注意:
UDF的用法同上。
UDF 仅适用于单个单元格输入范围。
通过存储单元格的最后一个值和 在文档属性中检测到更改的日期时间 工作簿。如果该公式用于大型数据集,则 对于跟踪的每个单元格,文件可能会大大增加 公式存储需求增加(单元格的最后一个值 + 最后更改的日期。)另外,也许 Excel 无法处理 非常大量的文档属性和代码可能会在 某一点。
如果更改工作表的名称,则其中包含的单元格的所有跟踪信息都会丢失。
代码可能会因转换为字符串不确定的单元格值而制动。
以下代码未经测试,仅应被视为证明 概念。 风险自负。
Public Function UDF_Date(ByVal inData As Range) As Date
Dim wb As Workbook
Dim dProps As DocumentProperties
Dim pValue As DocumentProperty
Dim pDate As DocumentProperty
Dim sName As String
Dim sNameDate As String
Dim bDate As Boolean
Dim bValue As Boolean
Dim bChanged As Boolean
bDate = True
bValue = True
bChanged = False
Dim sVal As String
Dim dDate As Date
sName = inData.Address & "_" & inData.Worksheet.Name
sNameDate = sName & "_dat"
sVal = CStr(inData.Value)
dDate = Now()
Set wb = inData.Worksheet.Parent
Set dProps = wb.CustomDocumentProperties
On Error Resume Next
Set pValue = dProps.Item(sName)
If Err.Number <> 0 Then
bValue = False
Err.Clear
End If
On Error GoTo 0
If Not bValue Then
bChanged = True
Set pValue = dProps.Add(sName, False, msoPropertyTypeString, sVal)
Else
bChanged = pValue.Value <> sVal
If bChanged Then
pValue.Value = sVal
End If
End If
On Error Resume Next
Set pDate = dProps.Item(sNameDate)
If Err.Number <> 0 Then
bDate = False
Err.Clear
End If
On Error GoTo 0
If Not bDate Then
Set pDate = dProps.Add(sNameDate, False, msoPropertyTypeDate, dDate)
End If
If bChanged Then
pDate.Value = dDate
Else
dDate = pDate.Value
End If
UDF_Date = dDate
End Function
【讨论】:
+1 这是一个很好的方法,你不能真正使用公式,因为所有时间相关的函数都是易变的,并且会立即重新计算 您好,感谢您的快速回答。我尝试了您发布的内容,但得到了#NAME?即使单元格已被格式化为显示日期。 #Name?可能意味着 Excel 找不到 UDF。您将 VBA 函数存储在哪里,是否声明为 Public,名称是否与您在 D2 中编写的内容相对应? @Roman:这可能会有点困难。在现实生活中,C2:C30 中的值来自其他工作簿(excel 文件)。 Fx: ='[workfile1.xlsx]Sheet1'!$W$32 @Roman:我通过按 Alt+F11 存储了 VBA 函数并将其粘贴到那里 - 并在 D2 中添加了 =UDF_Date(C2)。【参考方案2】:Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$C$2" Then
ActiveSheet.Range("D2").Value = Now()
End If
End Sub
【讨论】:
【参考方案3】:根据范围插入日期。
这样做的好处是除非单元格的内容发生变化,否则日期不会改变,并且在C2:C2范围内,即使工作表关闭并保存,也不会重新计算,除非相邻单元格发生变化.
改编自this tip 和@Paul S 的回答
Private Sub Worksheet_Change(ByVal Target As Range)
Dim R1 As Range
Dim R2 As Range
Dim InRange As Boolean
Set R1 = Range(Target.Address)
Set R2 = Range("C2:C20")
Set InterSectRange = Application.Intersect(R1, R2)
InRange = Not InterSectRange Is Nothing
Set InterSectRange = Nothing
If InRange = True Then
R1.Offset(0, 1).Value = Now()
End If
Set R1 = Nothing
Set R2 = Nothing
End Sub
【讨论】:
这看起来很优雅。会试一试。谢谢! ;o) 这仅在您手动更改范围内的数据时才有效(并且非常适合)。但是,如果您在单元格中有一个公式(就像我一样),它不会更新/更改进行更改的日期。因此,我无法使用它。对不起。 你的问题是“每当 C2 改变值(实际值,而不是公式)”所以我认为这意味着你实际上是在改变值,也许这还不清楚【参考方案4】:最简单的方法是添加=IF(B3="","Not Allocated",Now())
并将列的格式更改为所需的日期和时间格式。但是在这里,如果编辑 B 列,则需要更新的相应列的日期和时间将自动更新所有列,因为不检查旧值。但是如果可以获取当前时间,这可以很容易地使用。
【讨论】:
以上是关于当另一个单元格的值发生变化时,一个单元格中的自动日期更新(通过公式计算)的主要内容,如果未能解决你的问题,请参考以下文章