Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Delphi: How do I round a TDateTime to closest second, minute, five-minute etc?

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;
like image 329
Svein Bringsli Avatar asked Nov 08 '10 08:11

Svein Bringsli


2 Answers

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.

like image 176
z666zz666z Avatar answered Oct 13 '22 00:10

z666zz666z


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.

like image 32
gabr Avatar answered Oct 12 '22 22:10

gabr