Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

TimeStamp function 1

Status
Not open for further replies.

withanh

IS-IT--Management
Dec 17, 2008
221
US
I'm building a TimeStamp function for logging in a vbs app that I'm building. I don't want to use the Now() because that only shows to seconds, I want to show milliseconds. Some reading has shown that using the Timer() function may be better for my requirements.

I wrote the below code, but was wondering if there is a more efficient or better way of getting millisecond based time stamps.
Code:
Function TimeStamp()
  Dim Temp, iHour, iMinute, iSecond
  Temp = Timer/3600
  iHour = Int(temp)
  iMinute = Int((temp - iHour) * 60)
  iSecond = Int((((temp - iHour) * 60 - iMinute) * 60)*1000)/1000
  
  '2 digit hour
  If Len(iHour) < 2 Then
    iHour = "0" & CStr(iHour)
  Else
    iHour = CStr(iHour)
  End If
   
  '2 digit minute
  If Len(iMinute) < 2 Then
    iMinute = "0" & CStr(iMinute)
  Else
    iMinute = CStr(iMinute)
  End If
  
  '2 digit second
  If Len(Int(iSecond)) < 2 Then
    iSecond = "0" & CStr(iSecond)
  Else
    iSecond = CStr(iSecond)
  End If
  
  '3 digit hundredths
  If Len(iSecond) < 6 Then
    iSecond = iSecond & "0"
  End If
  
  TimeStamp = Date & " " & iHour & ":" & iMinute & ":" & iSecond
End Function
 
you can just do this:
iHour = right("00" & iHour, 2)
iMinute = right("00" & iMinute, 2)
iSecond = right("000000" & iSecond, 6)
 
Close, but when my millisecond ended with .78 my result was:

> 10/20/2009 11:30:010.78

Great idea...
 
ok, you have HH:MM:SS.MS right?
which one of these need to be 6 digits?
ms is milisecond?
what format is your time stamp?

 
>Some reading has shown that using the Timer() function may be better for my requirements.

Unfortunately your reading has led you astray. VBScript's Timer has neither the precision nor accuracy necessary for milliseconds timestamping

The precision of Timer is hundreths of a second. And the accuracy, which reflects how often the timer is actually refreshed and which depends on your OS and PC, will most likely be either 10 or 15ms.

Sadly I'm not aware of an easy way to get higher precision and accuracy timings for VBScript.
 
@strongm Understood, the inherent latency is close enough for me.

@wvdba You are correct, it is HH:MM:SS.MSx i.e. the seconds should be the 6 digits, (12.345) I want my output to look like 01:02:03.450 (or 01:02:03.400). I did update my formatting to plan for the "extra" 0...

h
 
>Understood, the inherent latency is close enough for me.

I'm not sure that you completely do.

>the seconds should be the 6 digits, (12.345)

The 5th digit (and beyond) is completely unachievable. Even the 4th digit is inaccurate.
 
Yes, I do understand.

And I mis-spoke, it is not 6 digits, it is 6 characters i.e. len("12.345") is = 6.

 
Ok, fair enough. Are you also aware that by

Temp = Timer/3600

(and the subsequent calculations) you are courting the risk of accumulating floating point errors that will sometimes artificially make it look like you have more accuracy than you actually do?

Am I right in assuming from what you have said that you do not actually want or need millisecond accuracy you just want a string that is formatted to appear as if it had millisecond accuracy?

In which case something like the following would work:

Code:
[blue]Public Function TimeStamp()
    Dim Temp, iHour, iMinute, iSecond
 
    Temp = CLng(Timer * 100) [green]' reduce floating point accuracy problem by moving to integer maths[/green]
    iHour = Temp \ 360000
    iMinute = (Temp - iHour * 360000) \ 6000
    iSecond = (Temp - iHour * 360000 - iMinute * 6000) / 100
    
    TimeStamp = vbsFormat(Date, "d") & vbsFormat(iHour, " 00") & vbsFormat(iMinute, ":00") & vbsFormat(iSecond, ":00.000")
End Function[/blue]

vbsFormat as used in the above is the function I showed in thread329-1570966, and include again here for completeness' sake:
Code:
[blue]Public Function vbsFormat(Expression, Format)
    vbsFormat = CoreFormat("{0:" & Format & "}", Expression)
End Function

[green]' Allows more of the .NET formatting functionality to be used directly if required[/green]
Public Function CoreFormat(Format, Expression)
    CoreFormat = Expression
    On Error Resume Next
    With CreateObject("System.Text.StringBuilder")
        .AppendFormat Format, Expression
        If Err = 0 Then CoreFormat = .toString
    End With
End Function[/blue]
 
strongm said:
Am I right in assuming from what you have said that you do not actually want or need millisecond accuracy you just want a string that is formatted to appear as if it had millisecond accuracy?
Yes, that's probably accurate. I just wanted it to match the other logs that are created outside of my control (My script calls a 3rd party executable that generates a log that shows the timestamp to the millisecond, so that's what I wanted my log to show.

In testing, your code always gave the thousandths digit of the seconds as a 0. I updated it to
Code:
Function TimeStamp()
  Dim Temp, iHour, iMinute, iSecond
 
  Temp = CLng(Timer * 1000) ' reduce floating point accuracy problem by moving to integer maths
  iHour = Temp \ 3600000
  iMinute = (Temp - iHour * 3600000) \ 60000
  iSecond = (Temp - iHour * 3600000 - iMinute * 60000) / 1000
    
  TimeStamp = vbsFormat(Date, "d") & vbsFormat(iHour, " 00") & vbsFormat(iMinute, ":00") & vbsFormat(iSecond, ":00.000")
End Function
and now it displays how I am expecting.

Thanks for the code snippets, they proved very helpful, condensing my code from 28 lines total to your 19 lines total. The speed/efficiency improvement is probably also an illusion since we're only talking a difference of 9 lines of code. It probably doesn't make much difference anyway since the illusion of accuracy is all that's technically required.

Thanks again!
 
>always gave the thousandths digit of the seconds as a 0

That's because it is always 0. As I said, and you acknowledged, Timer only returns hundreths of a second (and isn't even accurate to that). Trust me, my code is correct.

Your use of 1000 here reintroduces the floating point error. Allow me to demonstrate
Code:
[blue]    'Run from cscript in a console   
    Dim a, b, c
    
    lasta = 0
    starttime = Now
    Do Until DateDiff("s", starttime, Now) >= 1
        a = Timer

        b = CLng(a * 100)
        c = CLng(a * 1000)

        b = b / 100
        c = c / 1000

        If lasta <> a Then ' Only bother displaying when Timer actually ticks to a new value
            wscript.echo a & vbtab & b & vbtab &  c
            lasta = a
        End If

    Loop[/blue]

What you will see here is exactly what I've been telling you:

1) Timer only precise to hundreths of a second (column 1)
2) Timer not even accurate to hundreths - note how there are sometimes jumps of 2 hundreths of a second (column 1)
3) Your maths introduces floating point errors that have fooled you into thinking you have some milliseconds from Timer; you don't (column 3)
 
OK, I think I get it - and I appreciate your tenacity pounding it into my head :)

So what I'm seeing from the output is (column a) shows sometimes two and sometimes three repetitions, this means that the timer has only updated two or three times during that hundredth of the second, right? So then the thousandths (aka millisecond) is just an illusion. I'm still a little dense on the float point errors but in the following line
Code:
46365.23	46365.22	46365.228
I see that column a and column b are off, but based on what column c looks like column b should be 46365.23 and it's not so that must be the floating point error.

Am I close?
 
Not exactly. But close enough. Trouble is that playing with this this evening I've discovered a little idiosyncracy with the Timer that I was not previously aware - which is that there is a short period of the day when it does appear to have a precision of 1 millisecond ... which means that your use of 1000 may be the more desirable route to go ... I'm still investigating this discovery.
 
LOL, glad we're all learning from this :) I look forward to your discovery!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top