http://qs1969.pair.com?node_id=778585

Wire64 has asked for the wisdom of the Perl Monks concerning the following question:

Hi wisdom monks,
Im trying to write someting that will a number of display messages based on systemclock, ill try to explain.

Say i got 10 messages and i want to show one every 5 seconds. so 1 message shows when the time is between 0:00 and 0:04seconds;
2nd message will show 0:05 <-> 0:09 seconds. ... message 10 will show 0:45 <-> 0:49.
then message 1 will show again from 0:50 <-> 0:54. 2 will be 0:55 <-> 0:59
when minute 1 starts i want it to start with message 3, thats 1:00 <-> 1:04
My question is how do i calculate this :)
hope this makes sence, thanks in advanced,
Wire64

dont have much that will do the above but will show you where i'am at now.
#!/usr/bin/perl # # display stuff on systemclock use Switch; # Get current date & time my ($tsec,$tmin,$thour,$tday,$tmonth,$tyear,$twday,$tyday,$tisdst) = l +ocaltime(time); $showitems=10; $delay=5; $totalshowtime=$showitems*$delay; #calulate how many minutes it will take to complete $showminutes = $totalshowtime / 60; #remove everthing behind the . so we get a round number $showminutes =~ s/(\d)\.\d*/$1/; switch ($showminutes) { case /0/ { my $number= $tsec / ($showitems * $delay) ; print "$number\n"; #print "0\n"; } case /1/ {print "1\n"; } else {print "-$showminutes- did not match any\n";} } print "$showminutes | $totalshowtime = $showitems * $delay"; print "\n$tsec $tmin";

Replies are listed 'Best First'.
Re: display stuff based on systemclock
by ikegami (Patriarch) on Jul 09, 2009 at 15:55 UTC

    Something like this?

    my @mesages = (...); my $pass = 0; for my $message (@messages) { sleep(5) if !$pass++; print($message); }

    sleep is interruptible and drift can occur if the loop body is non-trivial, so maybe the following would be better:

    use Time::HiRes qw( time sleep ); # Optional sub sleep_until { my ($e_time) = @_; for (;;) { my $dur = $e_time - time; last if $dur <= 0; sleep($dur); } } my @mesages = (...); my $s_time = time; for my $i (@messages) { sleep_until($s_time + 5*$i); print($message); }
      no i dont want it to use sleep, i want the program to exit after displaying the message.
      So when i execute the program at 7:05:02 i get a message and if i execute the program at 7:05:06 i get the next message. Should have explained that sorry. and i dont want to write to disk either.
        Forgetting we're dealing with times for a second, that's usually done using by subtracting the remainder of a division by your slot size.
        $ perl -e'printf "%-3s %2d\n", "$_:", $_ - ($_ % 5) for 0..19' 0: 0 1: 0 2: 0 3: 0 4: 0 5: 5 6: 5 7: 5 8: 5 9: 5 10: 10 11: 10 12: 10 13: 10 14: 10 15: 15 16: 15 17: 15 18: 15 19: 15

        The same trick can be applied to times.

        $ perl -MPOSIX -le'@lt = localtime; $lt[0] -= $lt[0] % 5; print strfti +me "%Y-%m-%dT%H:%M:%S", @lt' 2009-07-09T12:14:40 $ perl -MPOSIX -le'@lt = localtime; $lt[0] -= $lt[0] % 5; print strfti +me "%Y-%m-%dT%H:%M:%S", @lt' 2009-07-09T12:14:40 $ perl -MPOSIX -le'@lt = localtime; $lt[0] -= $lt[0] % 5; print strfti +me "%Y-%m-%dT%H:%M:%S", @lt' 2009-07-09T12:14:45 $ perl -MPOSIX -le'@lt = localtime; $lt[0] -= $lt[0] % 5; print strfti +me "%Y-%m-%dT%H:%M:%S", @lt' 2009-07-09T12:14:45

        The question is what do you want to happen if 60 isn't divisible by $delay?

Re: display stuff based on systemclock
by ramlight (Friar) on Jul 09, 2009 at 17:49 UTC
    If I understand your problem correctly, you just want to display one of a number of messages based on the current time, then quit.

    UPDATE: As noted by Ikegami below, this is wrong!
    "So take the current time in seconds; mod it by the total number of seconds in a message cycle, and divide the results by the number of messages you have:"

    The correct formula (Thanks to Ikegami again) is (time / message-display-time) mod number-of-messages.

    # See correct version of this by ikegami below! @message = ("Message 1", "Message 2", "Message 3", "Message 4", "Message 5", "Message 6", "Message 7", "Message 8", "Message 9", "Message 10"); $num_msgs = @message; $msg_time = 5; $total_time = $num_msgs * $msg_time; $msg_num = int((time() % $total_time) / $num_msgs); print $message[$msg_num], "\n";

      Ah! That's what the OP meant. Unfortunately, there's a bug in your formula.

      It displays the first $msg_time messages for $num_msgs seconds.
      It should display the $num_msgs messages for $msg_time seconds.

      Fixed:

      my @message = ( "Message 1", "Message 2", "Message 3", "Message 4", "Message 5", "Message 6", "Message 7", "Message 8", "Message 9", "Message 10", ); my $msg_time = 5; print $message[ time / $msg_time % @message ], "\n";
        You are, of course, right. A little more time spent verifying my results would definitely have been worth while!