以下Excel VBA代码比较Variant数组中的日期成员和Date数组中累积小时数(一天的1/24)的效果。我有列C,E,G格式化为日期和D,F,H作为数字与很多d.p.s.在A列和B列中,我使用工作表函数复制了计算。在您尝试之前,您可能不会相信这一点,但Date的Variant数组的最后一个输出是提前1天。数字值(由VBA报告为39814.9999999999)在Excel中转换为39814.
编辑:当我说日期格式的C,E,G列时,我的意思是自定义“dd / mm / yyyy hh:mm:ss.00”。
以前有人见过这个吗?但更重要的是,我如何知道使用Variants时我可以信任什么?我需要维护数万行,Variant数组用于我们需要对Excel数据进行密集处理的所有地方。
Sub FillDatesBug()
Dim dtHours() As Date
Dim vHours As Variant
Dim vHours2 As Variant
Dim dtHour As Date
Dim dHour As Double
Dim i As Long
ReDim dtHours(1 To 25, 1 To 1)
ReDim vHours(1 To 25, 1 To 1)
ReDim vHours2(1 To 25, 1 To 1)
dtHour = CDate(1 / 24)
dHour = 1 / 24
dtHours(1, 1) = CDate(39814)
vHours(1, 1) = CDate(39814)
vHours2(1, 1) = 39814#
For i = 2 To 25
dtHours(i, 1) = dtHours(i - 1, 1) + dtHour
vHours(i, 1) = vHours(i - 1, 1) + dtHour
vHours2(i, 1) = vHours2(i - 1, 1) + dHour
Next i
Range("C2:C26").Value = dtHours
Range("D2:D26").Value = dtHours
Range("E2:E26").Value = vHours
Range("F2:F26").Value = vHours
Range("G2:G26").Value = vHours2
Range("H2:H26").Value = vHours2
Range("C28").Value = "dtHours(25,1) = " & dtHours(25, 1) & " or " & CDbl(dtHours(25, 1))
Range("E28").Value = "vHours(25,1) = " & vHours(25, 1) & " or " & CDbl(vHours(25, 1))
Range("G28").Value = "vHours2(25,1) = " & Format(vHours2(25, 1), "dd/mm/yyyy hh:mm:ss") & " or " & vHours2(25, 1)
End Sub
这是一个screenshot - 我显然没有代表显示它。
正如您所看到的,Date数组和具有Double成员的Variant数组得到了正确的答案(包括完全正常和理解的数字错误)。带有Date成员的Variant数组中的某些值会错误地转换为Excel。
第一个真正看到我在这里说的话的人赢得了我永恒的感激。
答案 0 :(得分:0)
编辑(更好的解释)。我在过去看过类似的东西,但不记得细节。在这种特殊情况下,它似乎至少部分与使用Variant数据类型并将结果写入工作表时发生的一些隐式数据转换有关。
如果必须使用Variant数组,一个修复方法是舍入到所需的精度级别。因此,您将进行以下更改,以进行舍入,例如以毫秒为单位:
For i = 2 To 25
vHours(i, 1) = Round((vHours(i - 1, 1) + dtHour) * 86400000, 0) / 86400000
dtHours(i, 1) = Round((dtHours(i - 1, 1) + dtHour) * 86400000, 0) / 86400000
Next I
编辑其他观察
如果使用Range.Value2
属性将变量数组写回工作表,而不是Range.Value
属性,则工作表单元格中显示的日期将是正确的。但是,公式栏中显示的日期将不正确(比预期提前一天)。这似乎是一个Excel问题,因为一个值,例如直接输入到单元格中的39814.99999999999也将在公式栏与工作表单元格中显示不同的日期。
在处理这个(以及其他问题)时,最安全,最快速的方法是在变量数组和工作表之间读/写时使用Value2
属性。有趣的讨论here,以及威廉姆斯在回应中提到的链接。
如果您希望公式栏和工作表单元格中的日期一致,我认为除了舍入之外别无选择。但这可能没有必要。
答案 1 :(得分:0)
我的结论是 - 使用range.Value = array将包含Date元素的Variant数组复制到Excel中是不安全的。有一个错误只发生在这种情况下,显然只有当值非常接近并且可能小于整数时才会出现。
Excel 2003,2007,2010,2013中存在错误...我尚未安装2016。
Date数组正常,包含Doubles的Variant数组正常。包含日期的Variant数组可以使用
一次转换为Double one元素array(i,j) = CDbl(array(i,j))
然后又安全了。 VBA中的算法在所有三种情况下都是相同的 - 日期内的VBA是VBA的双打,您可以在算术语句中互换使用它们。除了格式化,日期也是Excel的双打。它只是以一种特定的方式从一个处理到另一个,触发了一小部分内部转换代码,它将小数部分向上舍入,整数部分向下舍入。
编辑:Ron建议使用.Value2代替.Value,并且比转换为Double更加整洁(和更快)。谢谢,罗恩。全球搜索和替换,我们在这里......