Range.Find在VBA Excel中1月到11月(2月和12月)没有区别

时间:2018-02-22 16:14:30

标签: excel vba excel-vba date datetime

让我说我有以下琐碎的任务:

  • 连续写下2016年1月至2018年6月的第一个日期
  • 查找2016年1月1日,并将其涂成红色
  • 使用Range.Find()

因此,我创建了一个代码,循环从1到30并写下每个月的第一个日期。然后我使用Rows(1).Find(CDate("01.01.2016"))Rows(1).Find(DateSerial(2016,1,1)),我认为我的任务几乎准备就绪。

我运行代码,我在Excel 2010和Excel 2016中都看到了这一点:

enter image description here

问题: 它背后有什么理由吗?或者记录的Range.Find()函数是这样的吗?

Public Sub TestMe()

    Cells.Clear

    Dim cnt             As Long
    For cnt = 1 To 30
        Cells(1, cnt) = DateAdd("M", cnt - 1, DateSerial(2016, 1, 1))
        Cells(1, cnt).NumberFormat = "MMM-YY"
    Next cnt

    Dim foundRange      As Range
    Set foundRange = Rows(1).Find(CDate("01.01.2016"))
    'Set foundRange = Rows(1).Find(DateSerial(2016, 1, 1))  'the same false result
    'Set foundRange = Rows(1).Find("01.01.2016")             'does not find anything
    If Not foundRange Is Nothing Then
        foundRange.Interior.Color = vbRed
    End If

End Sub

通常,Range.Find()有一个可选的After参数,它是Range的第一个单元格。在我们的例子中,After参数被省略,因此它被认为是A1并且最后被检查。如果您在第一个循环后停止代码并从Excel手动删除Nov 16,那么您继续执行代码,它将以红色返回单元格Jan 16

至于11月被认为是发现的,它会让它回归并且它不会更进一步。问题更像是 - 2016年11月1日的逻辑与 2016年1月1日相同,甚至是部分?

4 个答案:

答案 0 :(得分:10)

每当.Find(LookAt:=xlPart)用于一系列日期时,日期不会与.Value2一致,但会按照美国日期格式以String静默转换为MM/DD/YY并查看此字符串。只要将单元格格式化为日期,Excel中日期的显示格式就完全不相关了。

因此,1月的每一天都可以在11月找到,2月的每一天都可以在12月找到,作为一个子串,在一个日历年内可能有58个(或闰年59个)不同的错误:

List of dates for comparison

为了避免这种错误,最好的解决方案是明确地查看xlWhole。如果未引用,Range.Find()将查找部分字符串。

另一个问题是Range.Find开始的地方。根据{{​​3}}它启动 AFTER 提供的或默认的单元格,并且仅在循环返回后查看起始单元格。

  

您希望搜索开始的单元格。这对应于从用户界面进行搜索时活动单元的位置。请注意,After必须是范围内的单个单元格。 请记住,搜索从此单元格开始;在方法回绕到此单元格之前,不会搜索指定的单元格。如果不指定此参数,则搜索将在范围左上角的单元格之后开始。

因此,通过不定义XlWhole和开始单元格,搜索到的第一个单元格为B1而非A1,并且在找到正确的日期之前,它会部分找到日期周围循环。

因此,在范围的末尾设置起始单元格将执行此操作:

Set foundRange = Rows(1).Find(DateSerial(2016, 1, 1), [XFD1])

The Documentation

答案 1 :(得分:1)

不确定为什么会发现11月1日,但您可以通过为Find()方法的可选LookAt参数指定值来修复它:

Set foundRange = Rows(1).Find(CDate("01.01.2016"), Lookat:=xlWhole)

答案 2 :(得分:0)

您可以使用以下格式

Set foundRange = Rows(1).Find(Format("1/1/2016", "MMM-YY"))

答案 3 :(得分:0)

我发现CDate不时行为不端。此代码似乎首先将您的日期转换为字符串,而不是日期的数字表示形式。在找到字符串后发生转换。由于您提到它跳过第一个单元格,因此包含该字符串的第一个日期是11/1/16。

debug.print cdate("01/01/16")
1/1/16

Set foundRange = Rows(1).Find(CDate(#1/1/2016#))
Debug.Print foundRange.Value2
42675