让我们说我有以下琐碎的任务:
Range.Find()
因此,我创建了一个代码,循环从1到30并写下每个月的第一个日期。然后我使用Rows(1).Find(CDate("01.01.2016"))
或Rows(1).Find(DateSerial(2016,1,1))
,我认为我的任务几乎准备好了。
我运行代码,我在Excel 2010和Excel 2016中看到了这一点:
问题:背后有什么理由吗?或者记录的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日相同,甚至是部分?
每当.Find(LookAt:=xlPart)
被用于一系列日期时,它的日期不是用他们的.Value2,而是按照美国日期格式 - String
默默地将它们转换为MM/DD/YY
并查看此字符串。只要将单元格格式化为日期,Excel中日期的显示格式就完全不相关了。
因此,1月的每一天都可以在11月找到,2月的每一天都可以作为子串在12月找到,在一个日历年内可能有58个(或闰年59个)不同的错误:
为了避免这个错误,最好的解决方案是明确地查看xlWhole
。如果没有引用,Range.Find()
会查找部分字符串。
另一个问题是Range.Find
开始的地方。根据The Documentation它在提供的或默认单元格之后开始,并且仅在循环返回后查看起始单元格。
您希望搜索开始的单元格。这对应于从用户界面进行搜索时活动单元的位置。请注意,After必须是范围内的单个单元格。请记住,搜索在此单元格之后开始;在方法回绕到此单元格之前,不会搜索指定的单元格。如果未指定此参数,则搜索将在范围左上角的单元格后面开始。
因此,通过不定义XlWhole
和一个起始单元格,搜索的第一个单元格是B1
而不是A1
,它会在循环找到正确的日期之前部分找到日期。
因此,将起始单元格设置在范围的末尾将执行以下操作:
Set foundRange = Rows(1).Find(DateSerial(2016, 1, 1), [XFD1])
不确定它为什么找到11月1日,但是您可以通过为Find()方法的可选LookAt参数指定值来修复它:
Set foundRange = Rows(1).Find(CDate("01.01.2016"), Lookat:=xlWhole)
您可以使用以下格式
Set foundRange = Rows(1).Find(Format("1/1/2016", "MMM-YY"))
我发现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