Link to home
Start Free TrialLog in
Avatar of eNarc
eNarcFlag for United Kingdom of Great Britain and Northern Ireland

asked on

How do I convert 04:05:04 to seconds?

How do I convert a Time Picker Box layout format of 04:05:04 to actual seconds?
Avatar of jimyX
jimyX

Is that format HH:MM:SS and you want to convert it to Seconds only?
Can you clarify more please?
SOLUTION
Avatar of jimyX
jimyX

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
drop TEdit and DateTimePicker and use the following code


procedure TForm1.Button1Click(Sender: TObject);
var Hour, Min, Sec, MSec : word;
begin
DecodeTime(DatetimePicker1.Time, Hour, Min, Sec, MSec);
Edit1.Text := IntToStr((360* Hour) + (Min * 60) + Sec);
end;

Open in new window

try this
uses
  DateUtils;

procedure TForm1.Button1Click(Sender: TObject);
var
  Secs: Int64;
begin
  Secs := ABS(SecondsBetween(Trunc(Now), DateTimePicker1.Time));
  ShowMessage(IntToStr(Secs));
end;

Open in new window

ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial

Actually the DateTimePicker.Time returns todays date & time, but only shows the time portion, thats why the calculation gives the correct answer. However if you happen to put in yesterdays date or some other date, then you are screwed
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Mine works just fine. Actually I do not see any difference between that method, except mine doesn't use unnecessary variables:
function ToSeconds(Tim:TDateTime):integer;
begin
  Result := (HourOf(Tim)*60*60) + (MinuteOf(Tim)*60) + SecondOf(Tim);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  showmessage(IntToStr(ToSeconds(DateTimePicker1.DateTime)));  //or just DateTimePicker1.Time
end;

Open in new window


LOL

All your methods end up calling more functions than a simple subtraction

jimyX
Your sample code calls DecodeTime three times so although you are not declaring the variables, you have a net effect of having the variables declared multiple times

Mahdi78
Thats the simplest version but DecodeTime still calls a couple of multiplication and divisions

Now what is more simpler than
 Secs := SecondsBetween(Trunc(Now), DateTimePicker1.Time)

Simply subtracting two float values and multiplying by Seconds per day

But I suppose performance is not the issue here

Now what is more simpler than
 Secs := SecondsBetween(Trunc(Now), DateTimePicker1.Time)

Well ewangoya, to start ruining your day, I could say that one need to know how a TTime is coded to understand how possibly it could work (use of Trunc function which operates on float values). So, not so simple in a way. And as we said sooner, this method can give some bad results

Then, SecondBetween is a bit of work in itself, if you look at its code

function SecondsBetween(const ANow, AThen: TDateTime): Int64;
begin
  Result := Abs(DateTimeToMilliseconds(ANow) - DateTimeToMilliseconds(AThen))
    div (MSecsPerSec);
end;
 that is 2 calls to DateTimeToMilliseconds, a substraction , a call to Abs and an integer division

function DateTimeToMilliseconds(const ADateTime: TDateTime): Int64;
var
  LTimeStamp: TTimeStamp;
begin
  LTimeStamp := DateTimeToTimeStamp(ADateTime);
  Result := LTimeStamp.Date;
  Result := (Result * MSecsPerDay) + LTimeStamp.Time;
end;
DateTimeToMilliseconds is a call to DateTimeToTimeStamp followed by a few calculations to translate a Date+ms into milliseconds

And DateTimeToTimeStamp, I will not post here as it is quite a load of ASM code to convert a float-based TDateTime into a TimeStamp structure (integer-based)

All those stacked calls are also quite costly in themselves.

on the other hand, DecodeTime is this :
procedure DecodeTime(const DateTime: TDateTime; var Hour, Min, Sec, MSec: Word);
var
  MinCount, MSecCount: Word;
begin
  DivMod(DateTimeToTimeStamp(DateTime).Time, SecsPerMin * MSecsPerSec, MinCount, MSecCount);
  DivMod(MinCount, MinsPerHour, Hour, Min);
  DivMod(MSecCount, MSecsPerSec, Sec, MSec);
end;
So only one call to DateTimeToTimeStamp, and 3 calls to DivMod which is an extremely compact and optimized function that "shift" the timestamp integer value into the Hour, Min, Sec and MSec.

In the end, DecodeTime is not only a lot easier to understand than your code using SecondsBetween, but I bet it is also faster by a factor of 3, maybe 4.

As a last word, I will say nevertheless that you are right about JimyX solution being much less effective than DecodeTime, as it is in fact calling it more than necessary behind the scene.
Never be afraid to declare 4 variables, that only cost 16 bytes in the stack, which are easily eaten up calling functions just to avoid them.

epasquire

(This is now just a discussion not part of solution)

SecondsBetween uses SpanOfNowAndThen which is simply Date1-Date2

The entire code of SecondsBetween comprises of  
  SecsPerDay * SpanOfNowAndThen(ANow, AThen);

It does not touch DateTimeToMilliseconds function

I totally agree this can give you bad results and DecodeTime is surely much simpler and cleaner,

Now comparing one Trunc to three DivMode, I think the Trunc will be faster
SecondsBetween uses SpanOfNowAndThen which is simply Date1-Date2

?? I gave you a complete analysis of the code from Delphi XE, how it is implemented. I have no SpanOfNowAndThen in that DateUtils code. Which Delphi version do you have ??

Delphi 2010

Same with Delphi 7, both use SpanOfNowAndThen

I don't have Delphi XE, so it seems they are implemented differently
I have checked in Delphi 7 it is a better implementation than in Delphi XE...
Those routines do not exist in Delphi 5, that I use also.

Well, it can barely be more straightforward than DecodeTime if you want something that can compile reliably on all Delphi versions, otherwise, if the goal is to get sure not one CPU cycle is wasted, then :

Function TimeToSeconds(T:TTime):Cardinal;
begin
 Result:=Trunc(Frac(T)*3600*24);
end;

Open in new window


But you must admit that it is less readable for the regular guy who is not well aware of Delphi way of coding date/time

Ok, now I think we have made all the talking possible about that simple subject :o)
Avatar of eNarc

ASKER

Thankyou so much.
Avatar of eNarc

ASKER

These are the functions I'm using.
function A(a:String):int64;
var
  H,M,S,MS:word;
begin
  DecodeTime(StrToTime(a),H,M,S,MS);
  Result:=H*3600+M*60+S;
end;

function B(a:String):int64;
var
  t:TDateTime;
begin
  t:=StrToTime(a);
  Result:=(HourOf(t)*60*60)+(MinuteOf(t)*60)+SecondOf(t);
end;

Open in new window

Avatar of eNarc

ASKER

>>>>ID:35731252 Author:epasquier

your code works Perfectly and is such a simple way, I hadn't seen it until I accepted. Apologies.
function C(a:String):Int64;
begin
 Result:=Trunc(Frac(StrToTime(a))*3600*24);
end;

Open in new window