粘贴到Excel中的Variant数组中的日期有时会丢失一天

时间:2017-01-23 21:45:39

标签: excel vba date variants

以下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。

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

2 个答案:

答案 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更加整洁(和更快)。谢谢,罗恩。全球搜索和替换,我们在这里......