使用VBA Now vs. Now()时的时差?

时间:2016-06-06 21:49:54

标签: excel vba excel-vba

需要了解为什么我会有时间差异。 这是我的VBA代码:

    Public OHLCArray(1 To 481, 0 To 28, 0 To 3) As Single
    'debug stmt below
    Dim DebugTime As Double

    OHLCArray(1, 0, 3) = Now()
    'next 3 lines are debugging lines
    DebugTime = OHLCArray(1, 0, 3)
    Print #1, "Now()=" & DebugTime
    Print #1, Now & "Debug print line - (just before pushing"

以下是日志文件中的调试输出行:

    Now()=42527.4609375
    06/06/2016 11:01:00 AMDebug print line - (just before pushing

你知道吗,时间是0.4609375 = 11:03:45 AM;我期待在第二个Print语句中向我显示这个,或者在不超过2秒的时间内关闭。

我的问题:在上面的例子中,为什么我会有不同的时间? now和now()之间有区别吗?这会影响时间的捕获吗,如上图所示?

感谢您的帮助。卡尔。

P.S。以下是上面确定的行之前的2个调试输出行:

    06/06/2016 10:59:34 AM - Skipped ws_calculate routine - CurrentTimeID already processed - CurrentTimeID = 45
    06/06/2016 10:59:54 AM - Skipped ws_calculate routine - CurrentTimeID already processed - CurrentTimeID = 45

P.S.S。以下是相关主题的链接 - 不确定它是否适用于我的问题:Postgres now() vs 'now' in function

P.S.S。谢谢Vegard。在检查具有类似输出数据的其他日志文件时,可以确定由于两个错误而导致我的混淆:a)在将新的单个数据移动到它之前我没有将DebugTime重置为零(较小的小数位来自哪里)从单个重叠到双重?),和b)您的观察,单个数据类型转换为双数据类型是没有用的,因为最初移动到我的数组时发生截断全日期数据定义为单一。我想我会将我的数组维持为单一,但是,为了避免它的大小加倍,当99.8%的数组工作得很好时定义为单数。我可以在我的工作表的标题中接受最多约2分钟的时间(当数组被转移到它时)。我了解到在大多数应用程序中将日期/时间数据移动到Single数据类型是不够的。数据类型应为Double或DateTime。

P.S.S。最后: 今天(周三,上午11点左右)运行调试语句的逻辑向我展示了以下内容:     OHLCArray(1,0,3)=现在()
单个OHLCArray元素捕获date.time为42529.46。 Now()然而是42529.45905067(相当于上午11:01:02),这出现在我的print.debug和打印日志文件(正确)中。当现在被铸造时,它会四舍五入到.46     DebugTime = OHLCArray(1,0,3)
当数组元素被转换为DebugTime时,会拾取其他数字(错误地)。 DebugTime = 42529.46093750。这意味着上午11:03:45。这里也很有趣。当我稍后将该数组元素(42529.46)移动到我的Excel工作表(反映完整数组的工作表)时 - 格式化为仅显示该数字的单元格,我在工作表中上午11:03:45。因此,这意味着工作表中的单元格正在以与DebugTime = OHLCArray(1,0,3)语句完全相同的方式接收数字。因为记住,数组元素是42529.46。 0.46转换为11:02:24 am。

感谢VeGard的额外努力。我希望这一后续工作有助于您更深入地了解EXCEL和VBA表现出来的一些不太明显的方法。正如我总是告诉我的非计算机文化的朋友:“计算机永远不会错!”

3 个答案:

答案 0 :(得分:4)

在日期上下文中使用Single给出正确答案的任何实例都是极端巧合。

为了进一步说明为什么,基于Gary的回答,我已经改变了你的代码,以便数组声明为Double - 当我们想要比较实际正确的DoubleSingle - 施放到 - Double这是不正确的。

Sub testTime()
    Dim OHLCArray(1 To 481, 0 To 28, 0 To 3) As Double
    'debug stmt below
    Dim DblTime As Double, SngTime As Single

    OHLCArray(1, 0, 3) = Now()
    'next 3 lines are debugging lines
    DblTime = OHLCArray(1, 0, 3)
    SngTime = OHLCArray(1, 0, 3)

    Debug.Print "Doubletime: " & DblTime
    Debug.Print "Singletime: " & SngTime
    Debug.Print "             Date                  Double             Single     Double(single2)"
    Debug.Print "Singletime = " & CDate(SngTime) & " - " & CDbl(SngTime) & "    - " & CSng(SngTime) & " - " & CDbl(SngTime2)
    Debug.Print "Doubletime = " & CDate(DblTime) & " - " & CDbl(DblTime) & " - " & CSng(DblTime)
    Debug.Print "Now()      = " & Now() & " - " & CDbl(Now()) & " - " & CSng(Now())
    Debug.Print "Now        = " & Now & " - " & CDbl(Now) & " - " & CSng(Now)
End Sub

现在,让我们回顾一下输出。我已经运行了好几次,这清楚地说明了这个问题。观察在“Double”列的第一行中发生了什么(或者更确切地说,发生了什么),这是我们将单个转换为double的地方,并将其与正确的{{1}进行比较在下一行:

Double

请注意,对于使用Doubletime: 42528,3991666667 Singletime: 42528,4 Date Double Single Singletime = 07.06.2016 09:33:45 - 42528,3984375 - 42528,4 Doubletime = 07.06.2016 09:34:48 - 42528,3991666667 - 42528,4 Now() = 07.06.2016 09:34:48 - 42528,3991666667 - 42528,4 Now = 07.06.2016 09:34:48 - 42528,3991666667 - 42528,4 Doubletime: 42528,3995138889 Singletime: 42528,4 Date Double Single Singletime = 07.06.2016 09:33:45 - 42528,3984375 - 42528,4 Doubletime = 07.06.2016 09:35:18 - 42528,3995138889 - 42528,4 Now() = 07.06.2016 09:35:18 - 42528,3995138889 - 42528,4 Now = 07.06.2016 09:35:18 - 42528,3995138889 - 42528,4 Doubletime: 42528,3996180556 Singletime: 42528,4 Date Double Single Singletime = 07.06.2016 09:33:45 - 42528,3984375 - 42528,4 Doubletime = 07.06.2016 09:35:27 - 42528,3996180556 - 42528,4 Now() = 07.06.2016 09:35:27 - 42528,3996180556 - 42528,4 Now = 07.06.2016 09:35:27 - 42528,3996180556 - 42528,4 Doubletime: 42528,3998726852 Singletime: 42528,4 Date Double Single Singletime = 07.06.2016 09:33:45 - 42528,3984375 - 42528,4 Doubletime = 07.06.2016 09:35:49 - 42528,3998726852 - 42528,4 Now() = 07.06.2016 09:35:49 - 42528,3998726852 - 42528,4 Now = 07.06.2016 09:35:49 - 42528,3998726852 - 42528,4 Doubletime: 42528,4045486111 Singletime: 42528,41 Date Double Single Singletime = 07.06.2016 09:45:00 - 42528,40625 - 42528,41 Doubletime = 07.06.2016 09:42:33 - 42528,4045486111 - 42528,41 Now() = 07.06.2016 09:42:33 - 42528,4045486111 - 42528,41 Now = 07.06.2016 09:42:33 - 42528,4045486111 - 42528,41 的所有日期转换,时间戳实际上是长时间静态的,因为数据类型不能支持足够的数字。

将它投射到Single产生更多数字这一事实并不一定能使它正确 - 它会变得稍微准确一些,但仍然不正确。

所以问题似乎与DoubleNow无关!如我的示例所示,只要使用正确的数据类型,它们都会产生正确的结果。

您的第一个问题,即错误的时间戳,是由于数组是Now()而不是Single

您的第二个问题完全是其他问题,可能在您的代码中。要么你正在超载Double,要么可能更有可能,Now在运行时正在做一些时髦的事情。尝试使用PrintPrint语句添加前缀,然后将结果与日志文件进行比较,或者更好的是,根据documentation,更改此内容:

Debug.Print "Now: " & Now

到此:

Print #1, Now & "Debug print line - (just before pushing"

  

使用标准短日期格式将日期数据写入文件   由您的系统识别。当日期或时间组件时   缺少或为零,只有提供的部分被写入文件。

编辑:

至于将Print #1, CDate(Now) & "Debug print line - (just before pushing"转换为Single时出现的神秘的额外数字,这不是编译器所做的近似,正如我之前错误猜到的那样。这是数字如何表示的已知副作用,显然是计算机科学中的common topic

对于数字精度,请使用Decimal datatype

MSDN详细讨论了Visual Basic上下文中的浮点精度。

此处:https://msdn.microsoft.com/en-us/library/system.double.aspx?cs-save-lang=1&cs-lang=vb#Conversions

  

类型转换。 Double结构提供了显式接口   支持IConvertible接口的实现   任何两种标准.NET Framework数据类型之间的转换。   语言编译器也支持隐式转换值   Double值的所有其他标准数字类型。转换a   Double的任何标准数字类型的值都是加宽   转换并且不需要铸造操作员的用户或   转换方法。

     

但是,Int64和Single值的转换可以   涉及精度的损失。

     

精度问题最常影响转换为Double值的单值。

在这里:https://msdn.microsoft.com/en-us/library/system.single.aspx

  

例如,2/10,精确地用.2表示为小数   分数,由.0011111001001100表示​​为二进制分数,   模式“1100”重复到无穷大。在这种情况下,   浮点值提供了不精确的表示   它代表的数字。执行额外的数学   对原始浮点值的操作通常会增加其值   缺乏精确性。例如,如果您比较结果   将.3乘以10并将.3增加到.3九次,你会看到   加法产生不太精确的结果,因为它涉及八个   比乘法更多的操作。请注意,这种差异是   只有在使用“R”显示两个Single值时才会显现   标准数字格式字符串,如有必要,显示全部9   Single类型支持的精度数字。

答案 1 :(得分:1)

使用Single而不是Double会产生截断的排序:

Sub NotNow()
    Dim s As Single, d As Double

    s = Now
    d = Now

    Dim dt As Date, dt2 As Date

    dt = CDate(s)
    dt2 = CDate(d)
    MsgBox s & vbCrLf & d & vbCrLf & dt & vbCrLf & dt2
End Sub

enter image description here

答案 2 :(得分:1)

Now和Now()之间没有区别。您的示例中的差异是因为OHLCarray被声明为单个。当我宣布evrything为双倍的时候是相同的:


现在()= 42528.3594907407
42528.3594907407调试打印行 - (在推送之前

(顺便说一句,如果你想要准确的时间使用windows api调用高分辨率计时器)

Sub lg()
Dim OHLCArray(1 To 481, 0 To 28, 0 To 3) As Double
    'debug stmt below
    Dim DebugTime As Double

    OHLCArray(1, 0, 3) = Now()
    'next 3 lines are debugging lines
    DebugTime = OHLCArray(1, 0, 3)
    Debug.Print "Now()=" & DebugTime
    Debug.Print CDbl(Now) & "Debug print line - (just before pushing"
End Sub