Does there exist a routine in Delphi that rounds a TDateTime value to the closest second, closest hour, closest 5-minute, closest half hour etc?
UPDATE:
Gabr provided an answer. There were some small errors, possibly due to the complete lack of testing ;-)
I cleaned it up a bit and tested it, and here's the final(?) version:
function RoundDateTimeToNearestInterval(vTime : TDateTime; vInterval : TDateTime = 5*60/SecsPerDay) : TDateTime;
var
vTimeSec,vIntSec,vRoundedSec : int64;
begin
//Rounds to nearest 5-minute by default
vTimeSec := round(vTime * SecsPerDay);
vIntSec := round(vInterval * SecsPerDay);
if vIntSec = 0 then exit(vTimeSec / SecsPerDay);
vRoundedSec := round(vTimeSec / vIntSec) * vIntSec;
Result := vRoundedSec / SecsPerDay;
end;
Wow! guys, how do you complicate too much something so simple... also most of you loose the option to round to nearest 1/100 second, etc...
This one is much more simple and can also round to milisenconds parts:
function RoundToNearest(TheDateTime,TheRoundStep:TDateTime):TdateTime;
begin
if 0=TheRoundStep
then begin // If round step is zero there is no round at all
RoundToNearest:=TheDateTime;
end
else begin // Just round to nearest multiple of TheRoundStep
RoundToNearest:=Round(TheDateTime/TheRoundStep)*TheRoundStep;
end;
end;
You can just test it with this common or not so common examples:
// Note: Scroll to bottom to see examples of round to 1/10 of a second, etc
// Round to nearest multiple of one hour and a half (round to 90'=1h30')
ShowMessage(FormatDateTime('hh:nn:ss.zzz'
,RoundToNearest(EncodeTime(15,31,37,156)
,EncodeTime(1,30,0,0))
)
);
// Round to nearest multiple of one hour and a quarter (round to 75'=1h15')
ShowMessage(FormatDateTime('hh:nn:ss.zzz'
,RoundToNearest(EncodeTime(15,31,37,156)
,EncodeTime(1,15,0,0))
)
);
// Round to nearest multiple of 60 minutes (round to hours)
ShowMessage(FormatDateTime('hh:nn:ss.zzz'
,RoundToNearest(EncodeTime(15,31,37,156)
,EncodeTime(1,0,0,0))
)
);
// Round to nearest multiple of 60 seconds (round to minutes)
ShowMessage(FormatDateTime('hh:nn:ss.zzz'
,RoundToNearest(EncodeTime(15,31,37,156)
,EncodeTime(0,1,0,0))
)
);
// Round to nearest multiple of second (round to seconds)
ShowMessage(FormatDateTime('hh:nn:ss.zzz'
,RoundToNearest(EncodeTime(15,31,37,156)
,EncodeTime(0,0,1,0))
)
);
// Round to nearest multiple of 1/100 seconds
ShowMessage(FormatDateTime('hh:nn:ss.zzz'
,RoundToNearest(EncodeTime(15,31,37,141)
,EncodeTime(0,0,0,100))
)
);
// Round to nearest multiple of 1/100 seconds
ShowMessage(FormatDateTime('hh:nn:ss.zzz'
,RoundToNearest(EncodeTime(15,31,37,156)
,EncodeTime(0,0,0,100))
)
);
// Round to nearest multiple of 1/10 seconds
ShowMessage(FormatDateTime('hh:nn:ss.zzz'
,RoundToNearest(EncodeTime(15,31,37,151)
,EncodeTime(0,0,0,10))
)
);
// Round to nearest multiple of 1/10 seconds
ShowMessage(FormatDateTime('hh:nn:ss.zzz'
,RoundToNearest(EncodeTime(15,31,37,156)
,EncodeTime(0,0,0,10))
)
);
Hope this helps people like me, that need to round to 1/100, 1/25 or 1/10 seconds.
Something like that (completely untested, written directly in browser):
function RoundToNearest(time, interval: TDateTime): TDateTime;
var
time_sec, int_sec, rounded_sec: int64;
begin
time_sec := Round(time * SecsPerDay);
int_sec := Round(interval * SecsPerDay);
rounded_sec := (time_sec div int_sec) * int_sec;
if (rounded_sec + int_sec - time_sec) - (time_sec - rounded_sec) then
rounded_sec := rounded_sec + time_sec;
Result := rounded_sec / SecsPerDay;
end;
The code assumes you want rounding with second precision. Milliseconds are thrown away.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With