Recent

Author Topic: [SOLVED] Format elapsed seconds to format "1 day, 5 hours, 53 mins, 28 secs"  (Read 9175 times)

Gizmo

  • Hero Member
  • *****
  • Posts: 831
I need to format a period of time from StartTiome to EndTime into a human readable period of time. Not a date, but something like "1 day, 5 hours, 53 mins, 28 secs"

I don't know if I have been trying too hard, but I just can't quite get this to work. Ideas please?

Code: [Select]
var
  StartTime, EndTime : TDateTime;
  SecondsElapsed, MinutesElapsed : Int64;
  HoursElapsed  : integer;
  TimeElapsed : string;

begin
StartTime := Now;
// Something happens for a few hours
EndTime := Now;

SecondsElapsed := SecondsBetween(StartTime, EndTime);  // So i have the total number of whole seconds between start and end time
MinutesElapsed := MinutesBetween(StartTime, EndTime);   // So i have the total number of whole minutes between start and end time
HoursElapsed := HoursBetween(StartTime, EndTime);   // So i have the total number of whole hours between start and end time

TimeElapsed := // "1 day, 5 hours, 53 mins, 28 secs" is what I am after
« Last Edit: June 27, 2014, 12:38:17 am by Gizmo »

wp

  • Hero Member
  • *****
  • Posts: 13484
Re: Format elapsed seconds to format "1 day, 5 hours, 53 mins, 28 secs"
« Reply #1 on: June 25, 2014, 08:56:58 pm »
Suppose t is the time difference in days. (If you have the time in seconds, you have to divide them by
(24*60*60) to get the days, of course). Then:

Code: [Select]

function ElapsedTimeAsString(t: Double): String;
begin
  Result := IntToStr(trunc(t)) + ' day';
  if trunc(t) > 1 then Result := Result + 's';
  Result := Result + ', ' + FormatDateTime('h" minutes, "s" seconds"', frac(t));
end;

Or if you want it in hours, without the days split off, you can use the new [h] symbol in FormatDateTime (fpc trunk required):

Code: [Select]
function ElapsedHoursAsString(t: Double): String;
begin
  Result := FormatDateTime('[h]"hours, "n" minutes, "s" seconds', t, [fdoInterval]);
end;
« Last Edit: June 25, 2014, 09:02:29 pm by wp »

eric

  • Sr. Member
  • ****
  • Posts: 267
Re: Format elapsed seconds to format "1 day, 5 hours, 53 mins, 28 secs"
« Reply #2 on: June 26, 2014, 12:17:18 am »
Code: [Select]
var
  TimeDifference: TDateTime;
  TimeString: string;



  TimeDifference := EndTime - StartTime;
  TimeString := FormatDateTime('dd days, hh hours, nn minutes, ss seconds', TimeDifference);

Gizmo

  • Hero Member
  • *****
  • Posts: 831
Re: Format elapsed seconds to format "1 day, 5 hours, 53 mins, 28 secs"
« Reply #3 on: June 26, 2014, 09:59:15 pm »
Eric, thanks, but your post when compiled reports illegal formatting.

Wp : thanks for your suggestion, which compiles but I'm not getting what I expect.

If I let it run for say 50 seconds, I get 0 for everything. 0 days, 0 hours, 0 mins, 0 secs. When I run debug, TimeTakenSeconds shows 0, which explains the result. When I examine the values in StartTime and EndTime they say something like 41862.012345 and 41862.012350 (see screenshot). Now I'm assuming the decimal in those values is OK because they do return as valid start and end times elsewhere in the program when formatted with FormatDateTime("d/m/y h/m/s", var).

So the question is why is SecondsBetween returning 0 when according to the syntax it expects two TDateTime values and returns an Int64?  TimeTakenSecs : Int64, which is correct.
« Last Edit: June 26, 2014, 10:02:25 pm by Gizmo »

wp

  • Hero Member
  • *****
  • Posts: 13484
Re: Format elapsed seconds to format "1 day, 5 hours, 53 mins, 28 secs"
« Reply #4 on: June 26, 2014, 10:52:50 pm »
Sorry - I don't understand what you are doing. You seem to get somewhere a StartTime and an EndTime and want to know the time difference. What are the units of StartTime and EndTime? Seconds? Or are they TDateTime?

If they are TDateTime - what I'd suppose from the numbers you mention  - their difference is much less less than 50 sec, it's not even half a second:

Code: [Select]
procedure TForm1.Button1Click(Sender: TObject);
var
  t1, t2, dt: TDateTime;
  s: String;
begin
  t1 := 41862.012345;
  t2 := 41862.012350;
  dt := t2 - t1;
  //dt := EncodeTime(0, 0, 50, 0);  // this produces a time difference of 50 sec
  s := FormatDateTime('h:n:s.z', dt);
  ShowMessage(s);
end; 

And if they are TDateTime why do you work with SecondsBetween at all?

There must be something wrong with your time measurement. or with your understanding of the date/time data types. The code posted above is working, for sure! See this example:
Code: [Select]
procedure TForm1.Button1Click(Sender: TObject);
var
  StartTime, EndTime, dt: TDateTime;
  s: String;
begin
  StartTime := EncodeDate(2014, 1, 1);
  EndTime := EncodeDate(2014, 1, 2) + EncodeTime(12, 10, 20, 321);
  // 1 day + 12 hour + 10 minutes + 20 seconds + 321 ms later
  dt := t2 - t1;
  s := IntToStr(trunc(dt)) + 'day(s), ' + FormatDateTime('h "hour(s), "n" minute(s), "s" second(s), "z "milliseconds', dt);
  ShowMessage(s);
end;
« Last Edit: June 26, 2014, 11:02:28 pm by wp »

eric

  • Sr. Member
  • ****
  • Posts: 267
Re: Format elapsed seconds to format "1 day, 5 hours, 53 mins, 28 secs"
« Reply #5 on: June 26, 2014, 11:51:42 pm »
Quote
Eric, thanks, but your post when compiled reports illegal formatting.

Sorry, I got the literal strings wrong. This should work:

TimeString := FormatDateTime('dd" days", hh" hours", nn" minutes", ss" seconds"', TimeDifference);

Gizmo

  • Hero Member
  • *****
  • Posts: 831
Re: Format elapsed seconds to format "1 day, 5 hours, 53 mins, 28 secs"
« Reply #6 on: June 27, 2014, 12:38:05 am »
Eric

With :
Code: [Select]
StartTime:= Now;   
/// Some time goes by
EndTime := Now;
TimeDifference := EndTime - StartTime;
strTimeDifference := FormatDateTime('dd" days", hh" hours", nn" minutes", ss" seconds"', TimeDifference);
If I let the process run for 30 seconds I get : "30 days, 0 hours, 0 mins, 30 secs"
If I let the process run for 8 seconds I get : "30 days, 0 hours, 0 mins, 8 secs"
If I let the process run for 6 seconds I get : "30 days, 0 hours, 0 mins, 6 secs"

WP

StartTime is TDateTime
EndTime is TDateTime

By my understanding of the FPC command "SecondsBetween" was that it returned the number of whole seconds between between one date and the next and it expects two TDateTime vars, AThen and ANow (i.e, starttime and endtime) and it returns an Int64, i.e. the number of whole seconds, e.g. 8, or 60, or 50. So that's why I was trying to then convert those seconds to HH:MM:SS.

What I didn't realise until you explained it to me was that you could simply have 3 TDateTimes - StartTime, EndTime and then the difference between the two could also be measured as TDateTime and then formatted as ou demonstrated.

So this now works (thanks to both of you) and pasted for the benefit of others:

Code: [Select]
var
StartTime, EndTime, TimeDifference : TDateTime;
strTimeDifference : string;
begin
  // Compute the end time and how long it took. Only for the GUI.
  EndTime := Now;
  lblEndTimeB.Caption := FormatDateTime('dd/mm/yy hh:mm:ss', EndTime);
  TimeDifference := EndTime - StartTime;
  strTimeDifference := FormatDateTime('h" hrs, "n" min, "s" sec"', TimeDifference);
  lblTimeTakenB.Caption := strTimeDifference;end;
« Last Edit: June 27, 2014, 12:47:00 am by Gizmo »

 

TinyPortal © 2005-2018