解决Excel VBA时间毫秒不准确的问题

时间:2015-09-02 13:55:35

标签: excel vba

我正在使用excel时间格式“hh:mm:ss.000”,并通过VBA一次向连续行中的单元格添加50ms:

use std::collections::HashMap;

fn main() {
  let pairs = vec!(("foo", "bar"), ("toto", "tata"));
  let map: HashMap<&'static str, &'static str> = pairs.into_iter().collect();
  println!("{:?}", map);
}

所以你在2015年5月23日看到了下面的起源时间,事情开始很好:

Dim dblTimestamp As Double
dblTimestamp = Selection.Value ' origin timestamp
' Setup base time increment of 50ms over 20 minutes

 For i = 1 To Selection.Rows.Count
    Selection.Rows(i).Value2 = dblTimestamp + (2# / (864000# * 4#))
    dblTimestamp = dblTimestamp + (2# / (864000# * 4#))
 Next i

问题是几分钟后(~1840行)开始显示精度/舍入误差:

5/23/2015 05:30:00.000
05:30:00.050
05:30:00.100
05:30:00.150
05:30:00.200
05:30:00.250

然后在20分钟后,它更加明显:

05:31:32.100
05:31:32.149
05:31:32.199
05:31:32.249

我可以使用其他数据类型进行计算吗?或者我是否需要暴力并且每1840行添加一个额外的毫秒数? 我更喜欢在将时间步长更改为200ms

时也适用的解决方案

3 个答案:

答案 0 :(得分:1)

完成添加后,您需要对日期值进行舍入。 Excel日期存储为引擎盖下的数字,时间用小数表示。例如,42249.6282730324是02/09/2015(&lt;小数点左侧)15:04:43.550(&lt;小数点右侧)所以你需要舍入这个数字。这是一篇很好的文章,展示了如何使用INT,CEILING和MOD函数来完成这项工作。 http://exceluser.com/formulas/roundtime.htm

答案 1 :(得分:1)

这应该可以解决问题。请注意,我删除了您的“选择”参考,而是使用“Now()”作为时间戳并将值放在单元格A2到A20000中。在功能上,你可以将所有时间帮助程序的东西组合成一个单一的舍入函数,但我设计它的方式是感觉更加面向对象并展示更具适应性的范例。希望这会有所帮助。

'A type used to store time data
Type TimeHelper
    MS As Double
    BaseTime As Double
End Type
'Value to use as millisecond
Const MilSec = 1 / 86400000
Sub Test()
    Dim t As Double
    t = Now()
    Dim step As Double
    step = 75
    Dim TH As TimeHelper

    For i = 2 To 200000
        t = t + step * MilSec
        TH = GetTimeHelper(t)
        t = RoundMS(TH, step)
        Cells(i, 1).Value2 = t
    Next i

End Sub
Function GetTimeHelper(t As Double) As TimeHelper
    x = t
    'Unrounded Hours
    x = (x - Round(x, 0)) * 24
    'Unrounded Minutes
    x = (x - Round(x, 0)) * 60
    'Seconds as Milliseconds
    GetTimeHelper.MS = (x - Round(x, 0)) * 60000
    'Time rounded down to nearest minute by removing millisecond value
    GetTimeHelper.BaseTime = t - (GetTimeHelper.MS * MilSec)
End Function
Function RoundMS(TH As TimeHelper, m As Double)
    'Construct a time from basetime and milliseconds
    'with milliseconds rounded to nearest multiple of m
    RoundMS = TH.BaseTime + (Round(TH.MS / m, 0) * m) * MilSec
End Function

答案 2 :(得分:0)

我实际上只是决定检查每一行后的文本值,看看它是否以9结尾,然后在必要时添加毫秒:

Dim dblTimestamp As Double
dblTimestamp = Selection.Value ' origin timestamp
' Setup base time increment of 50ms over 20 minutes

 For i = 1 To Selection.Rows.Count
    Selection.Rows(i).Value2 = dblTimestamp + (2# / (864000# * 4#))
    dblTimestamp = dblTimestamp + (2# / (864000# * 4#))

    ' check to see if previous value ended in 9 indicating loss of precision
    ' e.g. 05:30:00.999 instead of 05:30:01.000
    If Right(Selection.Rows(i).Cells(1).Text,1)="9") Then
      dblTimestamp = dblTimestamp + (1#/86400000#) ' add 1 ms
      Selection.Rows(i).Value2 = dblTimestamp
    End If
 Next i

这对我的情况来说已经足够了,但是对于其他情况,P57的答案应该仍然足够好。