Argghhhh! Converting Milliseconds...

0 views
Skip to first unread message

calan

unread,
Mar 19, 2005, 4:02:46 AM3/19/05
to
I'm looking for a function that will convert Milliseconds into a string that
includes hours, minutes, seconds, and hundredth of a second. Should look
something like "24:59:59:99". If it's more than 999 hours, it should just
return "***"

I'm running into all sorts of problems with large time values (like more
than 100 days) because of overflow problems. I've tried typing the variables
differently, and using casting conversions on the results.

More importantly, the hours don't seem right if I enter a certain number of
minutes more than 60. What I have so far is shown below.

I can't seem to find this on google for classic VB. Any ideas?

TIA as always!

Calan

****************

Public Function MillisecondsToTime(ms As Single, Optional IncludeHundreths
As Boolean = False, Optional IncludeLabels As Boolean = False) As String
Dim hours As Single
Dim mins As Single
Dim secs As Single
Dim hundreths As Single

hours = CLng(ms / 3600000)
mins = CLng(ms / 60000 Mod 60)
secs = CLng(ms / 1000 Mod 60)
hundreths = CInt((ms Mod 1000) / 10)

If hours > 999 Then
MillisecondsToTime = "***"
Exit Function
End If

If IncludeLabels Then
MillisecondsToTime = "H:" & Format(Hours, "0#") & " M:" & Format(mins,
"0#") & " S:" & Format(secs, "0#")
Else
MillisecondsToTime = Format(Hours, "0#") & ":" & Format(mins, "0#") &
":" & Format(secs, "0#")
End If

If IncludeHundreths Then
If IncludeLabels Then
MillisecondsToTime = MillisecondsToTime & " H:" & Format(hundreths,
"0#")
Else
MillisecondsToTime = MillisecondsToTime & ":" & Format(hundreths,
"0#")
End If
End If

End Function

****************


Rick Rothstein

unread,
Mar 19, 2005, 9:39:19 AM3/19/05
to
> I'm looking for a function that will convert Milliseconds into a
string that
> includes hours, minutes, seconds, and hundredth of a second. Should
look
> something like "24:59:59:99". If it's more than 999 hours, it should
just
> return "***"
>
> I'm running into all sorts of problems with large time values (like
more
> than 100 days) because of overflow problems. I've tried typing the
variables
> differently, and using casting conversions on the results.
>
> More importantly, the hours don't seem right if I enter a certain
number of
> minutes more than 60. What I have so far is shown below.
>
> I can't seem to find this on google for classic VB. Any ideas?
>
> TIA as always!
>
> Calan
>
> ****************
>
> Public Function MillisecondsToTime(ms As Single, Optional
IncludeHundreths
> ......<<snip>>.......

Here is the function I have come up with.

Function MillisecondsToTime(MS As Long, _
Optional IncludeHundreths As Boolean = False, _


Optional IncludeLabels As Boolean = False) As String

Dim Hours As Long
Dim Minutes As Long
Dim Seconds As Currency
Dim Hundreds As Long
Const MSperHour As Long = 360000
Const MSperMinute As Long = 6000
Const MSperSecond As Long = 100
If MS / MSperHour > 999 Then
MillisecondsToTime = "***"
Else
Hours = Int(MS / MSperHour)
Minutes = Int((MS - (Hours * MSperHour)) / MSperMinute)
Seconds = (MS - (Hours * MSperHour) - _
(Minutes * MSperMinute)) / MSperSecond
Hundreds = MSperSecond * (Seconds - Int(Seconds))
Seconds = Int(Seconds)
If IncludeLabels Then
MillisecondsToTime = "H:" & Format(Hours, "0# ") & _
"M:" & Format(Minutes, "0# ") & _
"S:" & Format(Seconds, "0#")
Else
MillisecondsToTime = Format(Hours, "0#") & _
":" & Format(Minutes, "0#") & _
":" & Format(Seconds, "0#")


End If
If IncludeHundreths Then
If IncludeLabels Then

MillisecondsToTime = MillisecondsToTime & " H:" & _
Format(Hundreds, "0#")
Else
MillisecondsToTime = MillisecondsToTime & ":" & _
Format(Hundreds, "0#")
End If
End If
End If
End Function

Rick - MVP

AK

unread,
Mar 19, 2005, 4:21:42 PM3/19/05
to
You have a bug in it, Rick
It originates from the constants.
They needs one more zero.
And have one more constant of 100
to use for the mask.

Try to convert 61742 milliSeconds.
From head it gives: H:00 M:01 S:01 H:74
The Function reveals
H:00 M:10 S:17 H:42

"Rick Rothstein" <rickNOS...@NOSPAMcomcast.net> skrev i en meddelelse
news:vPSdnScv364...@comcast.com...

Steve Gerrard

unread,
Mar 19, 2005, 8:09:37 PM3/19/05
to

"AK" <a...@myspamtrap.com> wrote in message
news:423c97e7$0$687$edfa...@dread16.news.tele.dk...

> You have a bug in it, Rick
> It originates from the constants.
> They needs one more zero.
> And have one more constant of 100
> to use for the mask.
>
> Try to convert 61742 milliSeconds.
> From head it gives: H:00 M:01 S:01 H:74
> The Function reveals
> H:00 M:10 S:17 H:42
>
>

Quite right, ako, a millisecond is 1/1000 of a second. Also, once you fix that,
the function should also round off the seconds if you choose not to display
milliseconds, e.g. your example of 61742 should show M:01 S:02.

Const MSperHour As Long = 3600000
Const MSperMinute As Long = 60000
Const MSperSecond As Long = 1000

Function MillisecondsToTime(MS As Long, _

Optional IncludeMilliSecs As Boolean = False, _


Optional IncludeLabels As Boolean = False) As String
Dim Hours As Long
Dim Minutes As Long
Dim Seconds As Currency

Dim MilliSecs As Long

Hours = Int(MS / MSperHour)
Minutes = Int((MS - (Hours * MSperHour)) / MSperMinute)
Seconds = (MS - (Hours * MSperHour) - _
(Minutes * MSperMinute)) / MSperSecond

MilliSecs = MSperSecond * (Seconds - Int(Seconds))
Seconds = Int(Seconds)

If Not IncludeMilliSecs Then
If MilliSecs >= MSperSecond / 2 Then
Seconds = Seconds + 1
If Seconds > 59 Then
Seconds = 0
Minutes = Minutes + 1
If Minutes > 59 Then
Minutes = 0
Hours = Hours + 1


End If
End If
End If

End If

If IncludeLabels Then
MillisecondsToTime = "H:" & Format(Hours, "0# ") & _
"M:" & Format(Minutes, "0# ") & _
"S:" & Format(Seconds, "0#")
Else
MillisecondsToTime = Format(Hours, "0#") & _
":" & Format(Minutes, "0#") & _
":" & Format(Seconds, "0#")
End If

If IncludeMilliSecs Then
MillisecondsToTime = MillisecondsToTime & "." & _
Format(MilliSecs, "0#")
End If

End Function


Private Sub Command1_Click()
Debug.Print Me.MillisecondsToTime(61742, True)
Debug.Print Me.MillisecondsToTime(61742, False)
Debug.Print Me.MillisecondsToTime(MSperHour - 1, True)
Debug.Print Me.MillisecondsToTime(MSperHour - 1, False)
End Sub

AK

unread,
Mar 20, 2005, 3:37:06 AM3/20/05
to

"Steve Gerrard" <mynam...@comcast.net> skrev i en meddelelse
news:0amdnerSU-m...@comcast.com...


'The OP doesn't want to append the decimalpart to the
'seconds. He want it to stand explicitly. Also, he want
'it expressed with 2 digits.
'To full fill this, I changed several among which;
'you can 't have MilliSecs As Long, as to round off
'seconds to two digits (up for third => 5).
I also changed the Dim'ing to Double, enthough
Currency would work. -But in certain cases,
there could be a long ripple (99...9) on the
decimalparts of seconds, where Currency wouldn't
suffice with its limit of 4 digit decimal.
Also, when making divisions with 2 Longs, the
result is rounded up on odd integer part left of
the decimalpart. Otherwise, it is rounded down.
This fact would really mess op the final result.

' Rick did it on purpose to call all Lurkes playing put!

ako

Function MillisecondsToTime(MS As Long, _

Optional IncludeHundreths As Boolean = False, _


Optional IncludeLabels As Boolean = False) As String

Dim Hours As Double
Dim Minutes As Double
Dim Seconds As Double
Dim Hundreds As Double
Dim MilliSecs As Double


Const MSperHour As Long = 3600000
Const MSperMinute As Long = 60000
Const MSperSecond As Long = 1000

If MS / MSperHour > 999 Then
MillisecondsToTime = "***"
Else

Hours = Int(MS / MSperHour)

Minutes = Int((MS - Hours * MSperHour) / MSperMinute)


Seconds = (MS - (Hours * MSperHour) - _
(Minutes * MSperMinute)) / MSperSecond

MilliSecs = Seconds - Int(Seconds)
Seconds = Int(Seconds)
If Not IncludeHundreths Then
If MilliSecs >= 0.5 Then


Seconds = Seconds + 1
If Seconds > 59 Then
Seconds = 0
Minutes = Minutes + 1
If Minutes > 59 Then
Minutes = 0
Hours = Hours + 1
End If
End If
End If
End If

If IncludeLabels Then
MillisecondsToTime = "H:" & Format(Hours, "0# ") & _
"M:" & Format(Minutes, "0# ") & _
"S:" & Format(Seconds, "0#")
Else
MillisecondsToTime = Format(Hours, "0#") & _
":" & Format(Minutes, "0#") & _
":" & Format(Seconds, "0#")
End If

If IncludeHundreths Then
If IncludeLabels Then
MillisecondsToTime = MillisecondsToTime & _
" H:" & Right(Format(MilliSecs, "0.00"), 2)
Else
MillisecondsToTime = MillisecondsToTime & _
":" & Right(Format(MilliSecs, "0.00"), 2)


End If
End If
End If

End Function


AK

unread,
Mar 20, 2005, 5:07:34 AM3/20/05
to
Correction:

Also, when making divisions with 2 Longs, the
result is rounded up on odd integer part left of
the decimalpart. Otherwise, it is rounded down.
This fact would really mess op the final result.

It is the CDbl that does the above.
The exact from help:
When the fractional part is exactly 0.5, CInt and
CLng always round it to the nearest even number.
For example, 0.5 rounds to 0, and 1.5 rounds to 2.
CInt and CLng differ from the Fix and Int functions,
which truncate, rather than round, the fractional
part of a number. Also, Fix and Int always return
a value of the same type as is passed in.

When Hours, MS and MSperHour is Long
Hours = MS / MSperHour
would be rounded up to 2
if decimalpart of division are = 1.5
if 2.5 it would be rounded down to 2
So it would produce mess in the calculation,

But I discovered the above rules is overRided
when wrapped with Int() as:


Hours = Int(MS / MSperHour)

Whether this is considered to be logical, is
a matter of taste in my opinion.

Conclusion: Dim'ing Hours, Minutes as Long
(as done originally) would also work.
To eliminate the needs to memorize such
remarkable things and the consequence of
humen memory-failure, I would make the
Dim'ing as Double.
ako


AK

unread,
Mar 20, 2005, 5:22:57 AM3/20/05
to
Rick, you really makes flutter
the dovecotes!.


AK

unread,
Mar 20, 2005, 5:41:39 AM3/20/05
to
Once more (got it mixed -all those pigeons.):

When Hours, MS and MSperHour is Long
Hours = MS / MSperHour
would be rounded up to 2
if decimalpart of division are => 1.5

if < 1.5 it would be rounded down to 2


So it would produce mess in the calculation,

But I discovered the above rules is overRided
when wrapped with Int() as:

Hours = Int(MS / MSperHour)

Whether this is considered to be logical, is
a matter of taste in my opinion.

ako


Rick Rothstein

unread,
Mar 20, 2005, 10:04:35 AM3/20/05
to
> You have a bug in it, Rick
> It originates from the constants.
> They needs one more zero.
> And have one more constant of 100
> to use for the mask.
>
> Try to convert 61742 milliSeconds.
> From head it gives: H:00 M:01 S:01 H:74
> The Function reveals
> H:00 M:10 S:17 H:42

You are correct... there is definitely a bug in my routine. Thank you
for noticing it and bringing it to my attention. Below is a corrected
routine which I think works correctly now. Thanks again.

Rick - MVP

Function MillisecondsToTime(MS As Long, _
Optional IncludeHundreths As Boolean = False, _
Optional IncludeLabels As Boolean = False) As String
Dim Hours As Long
Dim Minutes As Long
Dim Seconds As Currency

Dim RawSeconds As Currency
Dim Hundreds As Long
Const SecondsPerHour As Long = 3600
Const SecondsPerMinute As Long = 60
Const MSperSecond As Long = 1000
RawSeconds = MS / MSperSecond
Hours = Int(RawSeconds / SecondsPerHour)
If Hours > 999 Then
MillisecondsToTime = "***"
Else
Minutes = Int((RawSeconds - (Hours * _
SecondsPerHour)) / SecondsPerMinute)

Seconds = (RawSeconds - (Hours * SecondsPerHour) - _
(Minutes * SecondsPerMinute))
If IncludeHundreths Then
Hundreds = 100 * (Seconds - Int(Seconds))
Seconds = Int(Seconds)
Else
Seconds = Format$(Seconds, "00")
End If
If IncludeLabels Then
MillisecondsToTime = "H:" & Format(Hours, "00 ") & _
"M:" & Format(Minutes, "00 ") & _
"S:" & Format(Seconds, "00")


Else
MillisecondsToTime = Format(Hours, "0#") & _

":" & Format(Minutes, "00") & _
":" & Format(Seconds, "00")


End If
If IncludeHundreths Then
If IncludeLabels Then
MillisecondsToTime = MillisecondsToTime & " H:" & _

Format(Hundreds, "00")


Else
MillisecondsToTime = MillisecondsToTime & ":" & _

Format(Hundreds, "00")

Rick Rothstein

unread,
Mar 20, 2005, 10:23:35 AM3/20/05
to
> Once more (got it mixed -all those pigeons.):
>
> When Hours, MS and MSperHour is Long
> Hours = MS / MSperHour
> would be rounded up to 2
> if decimalpart of division are => 1.5
> if < 1.5 it would be rounded down to 2
> So it would produce mess in the calculation,
>
> But I discovered the above rules is overRided
> when wrapped with Int() as:
> Hours = Int(MS / MSperHour)

I think you are being tricked into thinking that by the numbers you are
using. The Int function always truncates the fractional part of any
floating point number. For example

Dim A As Long
Dim B As Long
A = 99
B = 98
Debug.Print Int(A / B)

No rounding is taking place. And you are right that simply dividing two
Long values and then putting that result into a Long variable will
perform Banker's Rounding (all rounding of numbers ending in 5 to the
previous decimal position is toward the nearest even number in that
position). This Banker's Rounding takes place in all rounding situations
except one... when you let the Format function perform the rounding. In
this case, the rounding method most people consider "normal" takes place
(5 and higher round up, less than 5 round down).

Debug.Print Format(3 / 2, "0")
Debug.Print Format(1 / 8, "0.00")

Rick - MVP

AK

unread,
Mar 20, 2005, 11:59:13 AM3/20/05
to

"Rick Rothstein" <rickNOS...@NOSPAMcomcast.net> skrev i en meddelelse
news:G8KdnX2bYYP...@comcast.com...

>> Once more (got it mixed -all those pigeons.):
>>
>> When Hours, MS and MSperHour is Long
>> Hours = MS / MSperHour
>> would be rounded up to 2
>> if decimalpart of division are => 1.5
>> if < 1.5 it would be rounded down to 2
>> So it would produce mess in the calculation,
>>
>> But I discovered the above rules is overRided
>> when wrapped with Int() as:
>> Hours = Int(MS / MSperHour)
>
> I think you are being tricked into thinking that by the numbers you are
> using. The Int function always truncates the fractional part of any
> floating point number. For example

No, I'm not being tricked, Rick. What I'm saying above is
not what you say:
I know how Int(...) works, both on positive and negative
numbers, and the Fix(..)

I se you changed the original


Hours = Int(MS / MSperHour)

to


RawSeconds = MS / MSperSecond

and droped the Int(..) around the right side.
Because RawSeconds is Dim'ed as Currency, you can
safe do this. As opposed, dropping Int(..) around the original;


Hours = Int(MS / MSperHour)

would lead to mess in the calculation, that is:
As Hours, MS and MSperHour is Dim'ed as Long,
Hours in the equation


Hours = MS / MSperHour

would be rounded up to 2 if the equations right side
division had a value of say =>1.5 but less than 2.
This situation would make a wrong calculation in the
conversion procedure.
Now, what I tried to point out at the top is:
Having MS / MSperHour wraped in Int(..) as
Hours = Int(MS / MSperHour) prevent divisions
of values between 1.5 and 1.99.. to round *up* to 2
That's what I were saying !.

I wonder how you could mis-understand this.
Never mind. I also se that you like Longs and
Currency. The later I too !.
ako

Rick Rothstein

unread,
Mar 20, 2005, 12:14:52 PM3/20/05
to
> I wonder how you could mis-understand this.

My mistake... I misread what you had written. Sorry.


> Never mind. I also se that you like Longs and
> Currency. The later I too !.

Currency is nice to work with (as long as you can work within its 4
decimal place limit) because it is really an integer value (kind of
number, not the data type) scaled to look like a floating point number.
Because of this, it does not suffer from the inaccuracies calculating
with floating point numbers can produce (again, as long as you can work
within its 4 decimal place limitation).


Rick

calan

unread,
Mar 21, 2005, 12:46:46 AM3/21/05
to
You guys rock... thanks much...


Reply all
Reply to author
Forward
0 new messages