13

我有一个包含许多日期的电子表格。这些通常出现在mm/dd/yyyymm/dd/yyyy hh:mm中。

问题是日期并不总是正确输入,我想检查以确保它们是代码中的日期。

我最初的想法是用来IsDate检查 orCDate但这似乎不起作用:它仍然返回字符串而不是日期。

从那以后,我进行了一个小型实验,表明这些功能并没有按照我期望的方式工作。方法论是:

  1. 在单元格 A1 中,我输入公式=DATE(2013,10,28)
  2. 单元格 B1 公式=A1*1应该等于一个数字 (41575)
  3. 运行这个小脚本

    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)。

所以我想总结一下问题:

  1. 为什么要将我的单元FormatCDate更改为字符串?
  2. 如何确保单元格将返回日期值而不仅仅是看起来像日期的字符串?
4

5 回答 5

17

区分单元格的内容、它们的显示格式、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
于 2013-11-06T10:20:02.483 回答
2

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
于 2013-11-06T00:13:02.550 回答
1

感谢您的输入。我显然看到了一些没有在其他机器上复制的问题。根据让的回答,我想出了似乎可行的不太优雅的解决方案。

因为如果我直接从 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
于 2013-11-06T17:02:20.530 回答
0

在侧面使用value(cellref)以评估细胞。字符串将产生“#Value”错误,但日期解析为数字(例如43173)。

于 2015-03-13T16:10:45.223 回答
0

为确保单元格将返回日期值而不仅仅是看起来像日期的字符串,首先必须将 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
于 2015-08-02T14:41:11.057 回答