Excel VBA 日期格式
Posted
技术标签:
【中文标题】Excel VBA 日期格式【英文标题】:Excel VBA date formats 【发布时间】:2013-11-17 01:42:38 【问题描述】:我有一个包含许多日期的电子表格。这些通常出现在mm/dd/yyyy
或mm/dd/yyyy hh:mm
中。
问题是日期并不总是正确输入,我想检查以确保它们是代码中的日期。
我最初的想法是使用 IsDate
来检查或使用 CDate
但这似乎不起作用:它仍然返回字符串而不是日期。
我已经建立了一个小实验,表明这些功能不能按我期望的方式工作。方法是:
-
在单元格 A1 中,我输入公式
=DATE(2013,10,28)
单元格 B1 公式 =A1*1
应该等于一个数字 (41575)
运行这个小脚本
Sub test()
MsgBox ("Start:" & TypeName(ActiveCell.Value) & " " & IsDate(ActiveCell.Value))
ActiveCell.Value = Format(ActiveCell.Value, "mm/dd/yyyy")
MsgBox ("After format: " & TypeName(ActiveCell.Value) & " " & IsDate(ActiveCell.Value))
ActiveCell.Value = CDate(ActiveCell.Value)
MsgBox ("After Cdate: " & TypeName(ActiveCell.Value) & " " & IsDate(ActiveCell.Value))
End Sub
当脚本启动时,单元格是日期类型,IsDate
返回 true。通过Format
运行后,它是字符串类型,但IsDate
仍然返回true。 CDate
还将单元格转换为字符串。单元格 B1 现在也将返回 0(因为它是一个字符串 *1)。
所以我想总结一下问题:
-
为什么
Format
和CDate
将我的单元格更改为字符串?
如何确保单元格返回日期值,而不仅仅是看起来像日期的字符串?
【问题讨论】:
【参考方案1】:Format
将值转换为字符串。 IsDate
仍然返回 true,因为它可以解析该字符串并获取有效日期。
如果您不想将单元格更改为字符串,请不要使用Format
。 (IOW,首先不要将它们转换为字符串。)使用Cell.NumberFormat
,并将其设置为您想要显示的日期格式。
ActiveCell.NumberFormat = "mm/dd/yy" ' Outputs 10/28/13
ActiveCell.NumberFormat = "dd/mm/yyyy" ' Outputs 28/10/2013
【讨论】:
嗯,不,CDate
converts to Date type,不是字符串。所以使用CDate
其实是个好主意。它不会将单元格的内容更改为字符串。
@Jean-FrançoisCorbett:感谢您的更正。自从我做任何 VBA 以来已经有一段时间了,我不记得使用 CDate
来做任何事情。我已经编辑更正了。【参考方案2】:
区分单元格的内容、它们的显示格式、VBA从单元格中读取的数据类型以及从 VBA 写入单元格的数据类型以及 Excel 如何自动解释这一点。 (参见例如this previous answer。)它们之间的关系可能有点复杂,因为 Excel 会执行诸如将一种类型(例如字符串)的值解释为某种其他数据类型(例如日期)然后自动更改 显示格式基于此。你最安全的赌注是它明确地做所有事情,而不是依赖这些自动的东西。
我运行了您的实验,但得到的结果与您不同。我的单元格 A1 始终保持日期,而 B1 保持 41575。所以我无法回答您的问题 #1。结果可能取决于您的 Excel 版本/设置如何选择根据其内容自动检测/更改单元格的数字格式。
问题 #2,“我如何确保单元格返回日期值”:嗯,不确定您所说的“返回”日期值是什么意思,但如果您希望它包含 根据您从 VBA 写入的内容,显示为日期的数值,然后您可以:
将您希望 Excel 自动解释为日期和格式的字符串值写入单元格。十指交叉。显然,这不是很健壮。或者,
从 VBA 向单元格写入一个数值(显然 Date 类型是预期的类型,但 Integer、Long、Single 或 Double 也可以)并将单元格的数字格式显式设置为您的使用 .NumberFormat
属性(或在 Excel 中手动)所需的日期格式。这要健壮得多。
如果您想检查现有单元格内容是否可以显示为日期,那么这里有一个功能会有所帮助:
Function CellContentCanBeInterpretedAsADate(cell As Range) As Boolean
Dim d As Date
On Error Resume Next
d = CDate(cell.Value)
If Err.Number <> 0 Then
CellContentCanBeInterpretedAsADate = False
Else
CellContentCanBeInterpretedAsADate = True
End If
On Error GoTo 0
End Function
示例用法:
Dim cell As Range
Set cell = Range("A1")
If CellContentCanBeInterpretedAsADate(cell) Then
cell.NumberFormat = "mm/dd/yyyy hh:mm"
Else
cell.NumberFormat = "General"
End If
【讨论】:
次要评论 - 在代码中尽快恢复错误处理是一种很好的做法,因此我会将“On Error GoTo 0”移高一行(在 if 语句之前)跨度> @Juliusz:不,那行不通。On Error Goto
将 Err
对象重置为零,因此您将无法判断是否发生错误,并且该函数将始终返回 True。如需更多信息,请查看this question,如果您有任何绝妙的想法,请告诉我!
@JFC 你完全正确!刚刚检查过。在这种情况下,您仍然会更好地分配错误编号并打开错误处理。在这个例子中,它不会有太大的不同,但如果使用更复杂的“if”语句,情况就会不同。
答案看起来不错,不幸的是代码在您的计算机上没有做同样的事情。使用您的代码,即使可以将单元格解释为日期,它仍然不会将单元格转换为数字,不知道为什么。它将格式更改为“mm/dd/yyyy hh:mm”,但它仍然只显示单元格中的字符串,并且没有数值。【参考方案3】:
感谢您的意见。我显然看到了一些没有在其他机器上复制的问题。根据 Jean 的回答,我想出了似乎可行的不太优雅的解决方案。
因为如果我直接从 cdate 向单元格传递一个值,或者只是将其格式化为数字,它会将单元格值保留为字符串,我必须先将日期值传递给数字变量,然后再将该数字传递回细胞。
Function CellContentCanBeInterpretedAsADate(cell As Range) As Boolean
Dim d As Date
On Error Resume Next
d = CDate(cell.Value)
If Err.Number <> 0 Then
CellContentCanBeInterpretedAsADate = False
Else
CellContentCanBeInterpretedAsADate = True
End If
On Error GoTo 0
End Function
示例用法:
Dim cell As Range
dim cvalue as double
Set cell = Range("A1")
If CellContentCanBeInterpretedAsADate(cell) Then
cvalue = cdate(cell.value)
cell.value = cvalue
cell.NumberFormat = "mm/dd/yyyy hh:mm"
Else
cell.NumberFormat = "General"
End If
【讨论】:
哇,这太奇怪了。我根本不需要做这个switcheroo。 +1 找出一个好的解决方法!【参考方案4】:使用侧面的value(cellref)
来评估单元格。字符串会产生“#Value”错误,但日期会解析为数字(例如43173
)。
【讨论】:
【参考方案5】:为确保单元格将返回日期值而不仅仅是看起来像日期的字符串,首先必须将 NumberFormat 属性设置为日期格式,然后将真实日期放入单元格的内容中。
Sub test_date_or_String()
Set c = ActiveCell
c.NumberFormat = "@"
c.Value = CDate("03/04/2014")
Debug.Print c.Value & " is a " & TypeName(c.Value) 'C is a String
c.NumberFormat = "m/d/yyyy"
Debug.Print c.Value & " is a " & TypeName(c.Value) 'C is still a String
c.Value = CDate("03/04/2014")
Debug.Print c.Value & " is a " & TypeName(c.Value) 'C is a date
End Sub
【讨论】:
以上是关于Excel VBA 日期格式的主要内容,如果未能解决你的问题,请参考以下文章