0

以下 Excel VBA 代码比较了 Variant 数组与 Date 成员以及 Date 数组中累积小时数(一天的 1/24)的效果。我将 C、E、G 列格式化为日期,将 D、F、H 列格式化为具有大量 dps 的数字 在 A 列和 BI 列中使用工作表函数复制了计算。在您尝试之前,您可能不会相信这一点,但是 Date 的 Variant 数组的最后输出是提前 1 天。VBA 报告为 39814.9999999999 的数值在 Excel 中转换为 39814。

编辑:当我说日期格式的列 C、E、G 时,我的意思是自定义“dd/mm/yyyy hh:mm:ss.00”。

有人见过这个吗?但更重要的是,我如何知道在使用 Variants 时我可以信任什么?我有数万行要维护,并且在我们需要对 Excel 数据进行密集处理的任何地方都使用 Variant 数组。

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

这是一个屏幕截图- 显然,我没有代表来显示它。

如您所见,一个 Date 数组和一个具有 Double 成员的 Variant 数组得到了正确的答案(包括完全正常和理解的数字错误)。带有 Date 成员的 Variant 数组中的某些值被错误地转换为 Excel。

第一个真正看到我在这里说的话的人会赢得我永远的感激。

4

2 回答 2

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在变量数组和工作表之间读/写时使用该属性。有趣的讨论在这里,以及威廉姆斯在他的回复中引用的链接。

如果您希望公式栏中的日期和工作表单元格中的日期一致,我认为除了舍入之外没有其他选择。但这可能没有必要。

于 2017-01-23T22:00:58.827 回答
0

我的结论是 - 使用 range.Value = array 将包含 Date 元素的 Variant 数组复制到 Excel 中是不安全的。只有在这种情况下才会出现一个错误,并且显然只有当该值非常接近并且可能小于整数时才会出现。

该错误存在于 Excel 2003、2007、2010、2013 中……我还没有安装 2016。

Date 数组可以,包含 Doubles 的 Variant 数组可以。包含 Dates 的 Variant 数组可以一次转换为 Double 一个元素

array(i,j) = CDbl(array(i,j))

然后它又安全了。VBA 中的算术在所有三种情况下都是相同的 - 日期在 VBA 内部是双精度数,您可以在算术语句中互换使用它们。除了格式,日期也是 Excel 的双精度数。它只是以这种特定方式从一个传递到另一个触发了内部转换代码的错误位,该代码将小数部分向上舍入,整数部分向下舍入。

编辑:Ron 建议使用 .Value2 而不是 .Value 有效,并且比转换为 Double 更整洁(更快)。谢谢,罗恩。全局搜索和替换,我们开始...

于 2017-01-24T15:03:23.410 回答