1. countdown display code

The following code displays a countdown intended to update every second. Most often the seconds display a decrement of 2 seconds, sometimes a 1 second decrement is displayed.

Is there an error in my code?

-- 
-- count_down.ex 
-- 
include std/datetime.e 
include std/math.e 
include std/graphics.e 
include std/os.e 
 
function DaysBetweenDates(datetime dt1,datetime dt2) 
atom d,h,m,s=diff(dt1,dt2) 
d=s/86400 
    h=frac(d)*24 -- hours.xxx 
    d=trunc(d)   -- days 
        m=frac(h)*60    -- minutes.xxx 
        h=trunc(h)      -- hours 
            s=frac(m)*60   -- seconds.xxx 
            m=trunc(m)     -- minutes 
                s=trunc(s)    -- seconds 
return {d,h,m,s} 
end function 
 
public procedure now_until(datetime dt2={2020,9,1,0,0,0}) 
sequence bal, pos = get_position() 
loop do 
    text_color(BRIGHT_WHITE) 
    position(pos[1],pos[2]) puts(1,"            ") position(pos[1],pos[2]) 
    text_color(BLUE) 
    bal=DaysBetweenDates(now(),dt2) 
    printf(1,"%d-%d:%d:%d",{bal[1],bal[2],bal[3],bal[4]}) 
    sleep(1) 
    until equal(bal,dt2)      
end loop 
end procedure 
 
 
now_until() 

Thanks, Ken

new topic     » topic index » view message » categorize

2. Re: countdown display code

Not exactly an error, more a misunderstanding of how truncate works, and Euphoria's printf() hiding what's really happening. trunc() returns the integer portion of a number, so even 9.9999999999 will come out as 9. That's not what's needed here.

--  
-- count_down.ex (revised) 
--  
include std/datetime.e  
include std/math.e  
include std/graphics.e  
include std/os.e  
include std/console.e 
atom s,t,r 
 
function DaysBetweenDates(datetime dt1,datetime dt2)  
atom d,h,m 
s=diff(dt1,dt2)  
d=s/86400  
    h=frac(d)*24 -- hours.xxx  
    d=trunc(d)   -- days  
        m=frac(h)*60    -- minutes.xxx  
        h=trunc(h)      -- hours  
            s=frac(m)*60   -- seconds.xxx  
            m=trunc(m)     -- minutes 
               t = trunc(s) 
               r = round(s,1) 
return {d,h,m,s}  
end function  
  
public procedure now_until(datetime dt2={2020,9,1,0,0,0})  
sequence bal, pos = get_position()  
object prevbal = 0 
loop do  
    bal=DaysBetweenDates(now(),dt2) 
        display("[]-[]:[]:[] ",bal,0) display("s=[] t=[] r=[]",{s,t,r}) 
    sleep(1) 
    until equal(bal,dt2)    
end loop  
end procedure  
  
now_until()  
 

The actual numbers are like this: s = raw seconds, t = trunc(s), r = round(s)

15-9:42:16 s=16 t=16 r=16 
15-9:42:15 s=15 t=14 r=15 
15-9:42:14 s=14 t=14 r=14 
15-9:42:13 s=13 t=12 r=13 
15-9:42:12 s=12 t=11 r=12 
15-9:42:11 s=11 t=11 r=11 
15-9:42:9.99999999999998 s=9.99999999999998 t=9 r=10 
15-9:42:9.00000000000002 s=9.00000000000002 t=9 r=9 
15-9:42:7.99999999999999 s=7.99999999999999 t=7 r=8 
15-9:42:7.00000000000004 s=7.00000000000004 t=7 r=7 
15-9:42:6 s=6 t=6 r=6 
15-9:42:4.99999999999997 s=4.99999999999997 t=4 r=5 
15-9:42:4.00000000000002 s=4.00000000000002 t=4 r=4 
15-9:42:2.99999999999998 s=2.99999999999998 t=2 r=3 
15-9:42:2.00000000000003 s=2.00000000000003 t=2 r=2 
15-9:42:0.999999999999996 s=0.999999999999996 t=0 r=1 
15-9:41:60 s=60 t=59 r=60 
15-9:41:59 s=59 t=59 r=59 
15-9:41:58 s=58 t=57 r=58 
 

Note: Will you have to use round instead of trunc for the minutes, hours and days as well?

new topic     » goto parent     » topic index » view message » categorize

3. Re: countdown display code

Here's a version that avoids nasty floating point math:

 
include std/os.e 
include std/console.e 
include std/datetime.e 
 
public procedure now_until(datetime dt={2021,12,25,12,0,0}) 
object dt1 -- (computer time and date) 
object dt2 = to_unix(dt)  
object target = datetime:format(dt,"%A, %b %d, %Y %l:%M:%S %p") 
object diff -- in seconds   
integer sec_now = 0, sec_prev = 0 
loop do  
    dt1 = to_unix(datetime:now()) 
    diff = dt2-dt1 
    diff = from_unix(diff)  
    diff -= {1970,1,1,0,0,0} -- adj for unix EPOCH 
    sec_now = diff[6] 
    if sec_now != sec_prev then 
        display("Time remaining: [b]-[b]-[b] []:[]:[]",diff,0) 
        display(" until []",{target}) 
        sec_prev = diff[6] 
    end if 
    sleep(.1) -- note: must check more than once per second, or time will "jitter" 
    until equal(dt1,dt2)    
end loop  
end procedure  
  
now_until()  
 

Now you know how much time you have to buy me a Christmas gift for next year:

Time remaining: 1-4-10 19:37:9 until Saturday, Dec 25, 2021 12:00:00 AM 
Time remaining: 1-4-10 19:37:8 until Saturday, Dec 25, 2021 12:00:00 AM 
Time remaining: 1-4-10 19:37:7 until Saturday, Dec 25, 2021 12:00:00 AM 

new topic     » goto parent     » topic index » view message » categorize

4. Re: countdown display code

Super WOW! Many thanks Irv!

Oh, and thanks for all the neat Pastey demos too. smile

Regards, Ken

new topic     » goto parent     » topic index » view message » categorize

5. Re: countdown display code

I revised Irv's 1st revision using round instead of trunc, display instead of printf and sleep(.1) instead of sleep(1) per his sample code.. works like charm.

Thanks, again,

function DaysBetweenDates(datetime dt1,datetime dt2)   
atom h,m,s=diff(dt1,dt2), 
d=s/86400     -- days.xx   
    h=frac(d)*24 -- hours.xxx   
    d=round(d,1) -- days 
        m=frac(h)*60      -- minutes.xxx   
        h=round(h,1)      -- hours   
            s=frac(m)*60     -- seconds.xxx   
            m=round(m,1)     -- minutes  
               s=round(s,1)     -- seconds  
return {d,h,m,s}   
end function   
   
public procedure now_until(datetime dt2={2021,1,20,0,0,0})   
sequence bal, pos = get_position()   
object prevbal = 0  
loop do 
    text_color(BRIGHT_WHITE)  
    position(pos[1],pos[2])  
    puts(1,"              ")     
    position(pos[1],pos[2])  
    text_color(BLUE) 
    bal=DaysBetweenDates(now(),dt2)  
    display("[]-[]:[]:[] ",bal,0)  
    sleep(.1)  
    until equal(bal,dt2)     
end loop   
end procedure   
   
now_until()   
 
-- 155-3:4:27 
new topic     » goto parent     » topic index » view message » categorize

6. Re: countdown display code

Good job but there is another way you could do it.

You see, the 0.9999 comes from repeating decimals which happens in binary as often as in base-10. You often get non-terminating decimal places after dividing.

You see 1/3 gives you a non-terminating decimal, but the computer will keep a limited set of decimals. Multiply this by 3 and you get 0.99999999. Now 1/86400 is a non-terminating decimal in both binary and decimal. So when you multiply the values you get this just shy of the correct value problem. If you avoid having this fraction in the first place, you avoid the problem.

atom t = floor(diff(d1,d2)) -- total_seconds.  A whole number but might be too big for integer type. 
integer s = remainder(t,60) -- the seconds part of the time 0..59 (always an integer!) 
t = floor(t/60) -- now total minutes 
integer m = remainder(t, 60) -- the minute part of the time  0..59 
t = floor(t/60) -- now total hours 
integer h = remainder(t,24)  -- hour part of the time. 
t = floor(t/24) -- now total days 
-- etc .... 
new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu