Hi John,
The code looks something like this:
lastTime := Time now asSeconds.
nextMinute := ((lastTime // 60) + 1) * 60.
[
currentTime := Time now asSeconds.
(currentTime >= lastTime) & (currentTime < nextMinute).
] whileTrue: [(Delay forMilliseconds: 500) wait].
The code is in a larger loop that I don't show. When it falls out of the #whileTrue: loop it is expected to be within the next minute. With the rounding up of #asSeconds, we can still be in the same minute, all be it close to the end of the minute.
The result of the problem wasn't terrible but it wasn't good either. I was keeping some activity counts by one minute intervals. Because of the problem those counts are askew again not terrible but bad enough.
Finding the problem wasn't fun either. I didn't expect the public #asSeconds method of #Time to change how it worked from one version to another. I know public methods can change, when the class changes and Time did get milliseconds added to it but I would have kept #asSeconds working as it was and added another method if the rounded value of seconds was needed.
The problem is fixed easy enough for this code. But I worry about other uses of #asSeconds and the problems that can be hiding out there, of mine and others.
For example:
EmTimeStamp class now
now
"Create a new time stamp with the current date and time. This can be incorrect
on some platforms if Time class>>#dateAndTimeNow does not ultimately use
a primitive that atomically answers the current date and time. If for example
the method just sends Date class>>#today and Time class>>#now, and the former
is sent before midnight and the latter is sent on or after midnight, the answer will be
out by twenty-four hours."
| dateAndTime |
dateAndTime := Time dateAndTimeNow.
^self new: (dateAndTime at: 1) asSeconds + (dateAndTime at: 2) asSeconds +
(self usingGMT
ifTrue: [3600 * self timeZonesFromGMT]
ifFalse: [0])
It seems to me that the above code (that is not mine) will fail even if a primitive is used if the time is just before midnight as the #asSeconds will round past midnight.
I also think this code (also not mine) might have problems if the passed in time rounds up to a time larger than now or maybe even vise versa.
StsPowerTools class
addTimeoutAt: aTime
receiver: receiver
selector: selector
clientData: clientData
| now then interval |
now := Time now asSeconds.
then := aTime asSeconds.
interval := then - now.
now >= then
ifTrue: [interval := interval + 86400].
self
addTimeout: interval * 1000
receiver: receiver
selector: selector
clientData: clientData
Also:
Time>putObjectOn: aStream
"Write into @aStream the byte representation of the receiver."
aStream nextPutIntegerAsFourBytes: self asSeconds
uses #asSeconds. I'm not sure if the rounding could cause a problem or not. I guess it depends where the data is going and if upon reading it in it is expected to be the same as was written.
Also please note that the display of a time value does not reflect the rounding up of the seconds:
((Time now) hours: 16 minutes: 37 seconds: 59 milliseconds: 600) asMilliseconds
59879600
(Time fromMilliseconds: 59879600)
4:37:59 PM
Time fromSeconds: ((Time fromMilliseconds: 59879600) asSeconds)
4:38:00 PM
Please don't take the above as a request to round up the seconds when displaying a time object. I just think that if the rounding was valuable, it would be used there.
Maybe I'm wrong about this as my friend Marten (who I respect greatly) suggests but I don't think so and I am curious if anyone out there has code that depends upon #asSeconds rounding the seconds?
Lou