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 (Pope) 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";