Recent

Author Topic: [SOLVED]Countdown timer woes  (Read 1172 times)

Lampbert

  • New Member
  • *
  • Posts: 33
[SOLVED]Countdown timer woes
« on: February 12, 2020, 10:54:38 pm »
Hello,

I am trying to make a countdown timer which counts down from 48 hours.

When the program is ran for the first time, the current date and time is assigned to the TargetTime variable. This string is then stored as a new registry value.

This string will never change throughout the program's life-cycle, so if the countdown is at 36:34:00 [hh:nn:ss], and the user closes the program and reopens the program exactly 5 minutes later, the countdown will read 36:29:00. And once the system time is equal or greater than the time written in the registry, the countdown will just be 00:00:00 (or negative numbers, I haven't gotten that far yet).

Here is my complete code (uses dateutils, registry):

Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormCreate(Sender: TObject);
  2. var
  3.   TargetTime: TDateTime;
  4.   TargetTimeString: string;
  5. begin
  6.   TargetTime := IncDay(Now, 2);
  7.   TargetTimeString := DateTimeToStr(TargetTime);
  8.  
  9.   with TRegistry.Create do try
  10.     RootKey := HKEY_CURRENT_USER;
  11.     OpenKey('\Software', False);
  12.       if not ValueExists('TargetTime') then begin
  13.         WriteString('TargetTime', TargetTimeString);
  14.       end;
  15.   finally
  16.     Free;
  17.   end;
  18. end;
  19.  
  20. procedure TForm1.Timer1Timer(Sender: TObject);
  21. var
  22.   TargetTime: TDateTime;
  23.   TargetTimeString: string;
  24.   TimeToTarget: TDateTime;
  25. begin
  26.   with TRegistry.Create do try
  27.     RootKey := HKEY_CURRENT_USER;
  28.     OpenKey('\Software', False);
  29.     TargetTimeString := ReadString('TargetTime');
  30.   finally
  31.   end;
  32.  
  33.   TargetTime := StrToDateTime(TargetTimeString);
  34.  
  35.   // Thanks to lucamar for the following code:
  36.   if Time > TargetTime then begin
  37.     Timer1.Enabled := False;
  38.   end else begin
  39.     TimeToTarget := TargetTime - Time;
  40.     // FormatDateTime('dd:hh:nn:ss', TimeToTarget);
  41.     Label1.Caption := TimeToStr(TimeToTarget);
  42.   end;
  43. end;  

The problem is, however many days I increment now by (line 6), although the value will be correct in the registry, the timer doesn't count down from that value (in [hh:nn:ss]) - it will always count down from 24 hours (in [hh:nn:ss]) instead. I need it to count down from 48 hours (hence incrementing it by 2)

Why will it never show more than 24 hours?
« Last Edit: February 13, 2020, 03:12:20 am by Lampbert »

jamie

  • Hero Member
  • *****
  • Posts: 6130
Re: Countdown timer woes
« Reply #1 on: February 12, 2020, 11:12:12 pm »
maybe I missed something but from what I see that code will reset you each time you restart, you'll always get 48 hours and so to keep it from timing out the app is simply restarted

 How about first testing for the existence for a register entry that is a newer data then the present and if so use that as the terminating time otherwise if the entry does not exists then create it or if it does exist and it has timed out then do what ever with it.

 I really don't think you need a registry entry for this, you can write a hidden INI file in the users folder.
The only true wisdom is knowing you know nothing

Lampbert

  • New Member
  • *
  • Posts: 33
Re: Countdown timer woes
« Reply #2 on: February 12, 2020, 11:28:42 pm »
Hi jamie,

Thanks for the input. The registry value will not reset each time it starts, because of the if statement - "If the value doesn't exist, write the value, otherwise, do nothing". I can see that the registry value does not change since the first time it was created, because I first ran the program at 21:39PM, and the value of the registry entry is "14/02/2020 21:39:09". When I ran the program just a minute ago (at 22:25PM), and forgot to remove this entry from last time, the countdown was at 23:13:50 - a testament to the fact that this part of the code works.

The only part that doesn't is that last part. For some reason TimeToTarget is never more than 24hrs, even though it should be 48 hours (because of the incrementing of now by 2 days on line 6). I just can't figure out why.

Lampbert

  • New Member
  • *
  • Posts: 33
Re: Countdown timer woes
« Reply #3 on: February 12, 2020, 11:54:06 pm »
Currently, the string that was written to the registry (incrementing "now" by 2 days) is:

Quote
14/02/2020 21:39:09

That is 100% correct.

Now, refer to line 39 of my code:

Code: Pascal  [Select][+][-]
  1. TimeToTarget := TargetTime - Time; // TargetTime being the date and time that was stored in the registry, Time being current system time

In other words:
Quote
14/02/2020 21:39:09 [subtact] 12/02/2020 22:53:00

...which should output 46:46:09, but it doesn't - it outputs 22:46:09.
« Last Edit: February 13, 2020, 12:08:57 am by Lampbert »

eljo

  • Sr. Member
  • ****
  • Posts: 468
Re: Countdown timer woes
« Reply #4 on: February 13, 2020, 12:07:16 am »
Currently, the string that was written to the registry (incrementing "now" by 2 days) is:

Quote
14/02/2020 21:39:09

That is 100% correct.

Now, refer to line 39 of my code:

Code: Pascal  [Select][+][-]
  1. TimeToTarget := TargetTime - Time; // TargetTime being the date and time that was stored in the registry

That is, 14/02/2020 21:39:09 [subtact] 12/02/2020 22:53:00 which should output roughly 46:45:00, but it doesn't - it outputs roughly 22:45:00.
OK a long since I used date time code so take a look on the code but datetime is floating point data type that has on the integer part the date and on the decimal part the time. timetostr should only try to translate the time part and ignore the date you need to multiply trunc(TimeToTarget) * 24 and add it to the final result manually or use the one of the existing functions to do it manually take a look on HoursBetween and friends

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2020
  • Former Delphi 1-7, 10.2 user
Re: Countdown timer woes
« Reply #5 on: February 13, 2020, 12:49:36 am »
Code: Pascal  [Select][+][-]
  1. Program TimeTest;
  2.  
  3. Uses SysUtils, DateUtils;
  4.  
  5. Var
  6.   TargetTime: TTime;
  7.   MyNow: TTime;
  8.   Hours: Int64;
  9.   Minutes: Int64;
  10.   Seconds: Int64;
  11.  
  12. Begin
  13.   TargetTime := IncHour(Now,48);
  14.    
  15.   Writeln('Two Days from today is ',DateTimeToStr(TargetTime));
  16.   Writeln('Now is ',DateTimeToStr(Now));
  17.  
  18.   WriteLn('Sleeping for  approx. 5 seconds');
  19.   Sleep(5000);
  20.  
  21.   MyNow := Now;
  22.   Hours := HoursBetween(MyNow,TargetTime);
  23.   Minutes := MinutesBetween(MyNow,TargetTime) - (Hours * 60);
  24.   Seconds := SecondsBetween(MyNow,TargetTime) - ((Hours * 60 * 60) + (Minutes * 60));
  25.  
  26.   WriteLn('Time to target ', Hours, ' hours ', Minutes, ' minutes ', Seconds, ' seconds');
  27. End.
  28.  

outputs:

Code: [Select]
Two Days from today is 15-2-20 10:51:04
Now is 13-2-20 10:51:04
Sleeping for  approx. 5 seconds
Time to target 47 hours 59 minutes 54 seconds
« Last Edit: February 13, 2020, 12:51:23 am by trev »

Lampbert

  • New Member
  • *
  • Posts: 33
Re: Countdown timer woes
« Reply #6 on: February 13, 2020, 03:12:03 am »
Code: Pascal  [Select][+][-]
  1. Program TimeTest;
  2.  
  3. Uses SysUtils, DateUtils;
  4.  
  5. Var
  6.   TargetTime: TTime;
  7.   MyNow: TTime;
  8.   Hours: Int64;
  9.   Minutes: Int64;
  10.   Seconds: Int64;
  11.  
  12. Begin
  13.   TargetTime := IncHour(Now,48);
  14.    
  15.   Writeln('Two Days from today is ',DateTimeToStr(TargetTime));
  16.   Writeln('Now is ',DateTimeToStr(Now));
  17.  
  18.   WriteLn('Sleeping for  approx. 5 seconds');
  19.   Sleep(5000);
  20.  
  21.   MyNow := Now;
  22.   Hours := HoursBetween(MyNow,TargetTime);
  23.   Minutes := MinutesBetween(MyNow,TargetTime) - (Hours * 60);
  24.   Seconds := SecondsBetween(MyNow,TargetTime) - ((Hours * 60 * 60) + (Minutes * 60));
  25.  
  26.   WriteLn('Time to target ', Hours, ' hours ', Minutes, ' minutes ', Seconds, ' seconds');
  27. End.
  28.  

outputs:

Code: [Select]
Two Days from today is 15-2-20 10:51:04
Now is 13-2-20 10:51:04
Sleeping for  approx. 5 seconds
Time to target 47 hours 59 minutes 54 seconds

Thank you, this solution works very well indeed - solved.

Still faintly on-topic, do you have any advice on smoothing out the countdown; it skips seconds every now and then, especially when my memory usage is high.

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: [SOLVED]Countdown timer woes
« Reply #7 on: February 13, 2020, 02:18:57 pm »
Trev's solution is good, but in case you're still looking for an explanation, your problem was with TimeToStr(). In a TDateTime the Time part never represents more than 23:59:59.999 so TimeToStr() can never show larger intervals.

To show them properly you have to use FormatDateTime(), for example with:
Code: Pascal  [Select][+][-]
  1. Label1.Caption := FormatDateTime('[hh]:nn:ss', TimeToTarget, [fdoInterval]);
« Last Edit: February 13, 2020, 02:22:40 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

Lampbert

  • New Member
  • *
  • Posts: 33
Re: [SOLVED]Countdown timer woes
« Reply #8 on: February 14, 2020, 01:13:09 pm »
Trev's solution is good, but in case you're still looking for an explanation, your problem was with TimeToStr(). In a TDateTime the Time part never represents more than 23:59:59.999 so TimeToStr() can never show larger intervals.

To show them properly you have to use FormatDateTime(), for example with:
Code: Pascal  [Select][+][-]
  1. Label1.Caption := FormatDateTime('[hh]:nn:ss', TimeToTarget, [fdoInterval]);

Thank you for that explanation - that explains why it was never more than 24hrs.

 

TinyPortal © 2005-2018