--- Available.pm 2003/10/03 16:40:00 1.3 +++ Available.pm 2003/10/06 20:59:11 1.8 @@ -3,6 +3,8 @@ use 5.001; use strict; use warnings; +use Carp; +use Time::Local; require Exporter; @@ -59,31 +61,50 @@ $self->{ARGS} = {@_}; $debug = $self->{ARGS}->{DEBUG}; - die("need start time") if (! $self->{ARGS}->{start}); + croak("need start time") if (! $self->{ARGS}->{start}); # calc start and stop seconds my ($hh,$mm,$ss) = split(/:/,$self->{ARGS}->{start},3); - my $s = $hh * 3600 || die("need at least hour specified for start time"); - $s += $mm * 60 if ($mm); - $s += $ss if ($ss); - $self->{start} = $s; + print STDERR "new: start time ",$hh||0,":",$mm||0,":",$ss||0,"\n" if ($debug); + croak("need at least hour specified for start time") if (! $hh); + $mm |= 0; + $ss |= 0; + $self->{start_arr} = [$ss,$mm,$hh]; + + my $start = $hh; + $start *= 60; + $start += $mm; + $start *= 60; + $start += $ss; - die("need end time") if (! $self->{ARGS}->{end}); + croak("need end time") if (! $self->{ARGS}->{end}); ($hh,$mm,$ss) = split(/:/,$self->{ARGS}->{end},3); - $s = $hh * 3600 || die("need at least hour specified for end time"); - $s += $mm * 60 if ($mm); - $self->{end} = $s; + print STDERR "new: end time ",$hh||0,":",$mm||0,":",$ss||0,"\n" if ($debug); + croak("need at least hour specified for end time") if (! $hh); + $mm |= 0; + $ss |= 0; + $self->{end_arr} = [$ss,$mm,$hh]; + + my $end = $hh; + $end *= 60; + $end += $mm; + $end *= 60; + $end += $ss; - die("need dayMask specified") if (! $self->{ARGS}->{dayMask}); + croak("need dayMask specified") if (! $self->{ARGS}->{dayMask}); $self->{dayMask} = $self->{ARGS}->{dayMask}; + # over midnight? + if ($start > $end) { + $self->{sec_in_interval} = (86400 - $start + $end); + } else { + $self->{sec_in_interval} = ($end - $start); + } $self ? return $self : return undef; } - - # # this sub (originally from Time::Avail) will return if day is applicable # @@ -117,6 +138,31 @@ return $dayOk; } +# +# calculate start and end of interval in given day +# + +sub _start { + my $self = shift; + my $t = shift || croak "_start needs timestap"; + + my @lt = localtime($t); + $lt[0] = $self->{start_arr}[0]; + $lt[1] = $self->{start_arr}[1]; + $lt[2] = $self->{start_arr}[2]; + return timelocal(@lt); +} + +sub _end { + my $self = shift; + my $t = shift || croak "_end needs timestap"; + + my @lt = localtime($t); + $lt[0] = $self->{end_arr}[0]; + $lt[1] = $self->{end_arr}[1]; + $lt[2] = $self->{end_arr}[2]; + return timelocal(@lt); +} # # this will return number of seconds that service is available if passed @@ -126,44 +172,87 @@ sub uptime { my $self = shift; - my $time = shift || die "need uptime timestamp to calcualte uptime"; + my $time = shift || croak "need uptime timestamp to calculate uptime"; # calculate offset -- that is number of seconds since midnight my @lt = localtime($time); - my $offset = $lt[2]; # hour - $offset *= 60; # convert to minutes - $offset += $lt[1]; # minutes - $offset *= 60; # convert to seconds - $offset += $lt[0]; # check if day falls into dayMask return 0 if (! $self->_dayOk($lt[6]) ); my $s=0; - my $start = $self->{start}; - my $end = $self->{end}; + my $start = $self->_start($time); + my $end = $self->_end($time); - print STDERR "start: $start end: $end time: $offset\n" if ($debug); + print STDERR "start: $start end: $end time: $time [$lt[2]:$lt[1]:$lt[0]]\n" if ($debug); if ( $end > $start ) { - if ($offset < $start) { + if ($time < $start) { $s = $end - $start; - } elsif ($offset < $end) { - $s = $end - $offset; + } elsif ($time < $end) { + $s = $end - $time; } } elsif ( $start > $end ) { # over midnight - if ( $offset < $end ) { - if ( $offset < $start) { - $s = SEC_PER_DAY - $start + $end - $offset; + if ( $time < $end ) { + if ( $time < $start) { + $s = SEC_PER_DAY - $start + $end - $time; } else { $s = SEC_PER_DAY - $start + $end; } } else { - if ( $offset < $start ) { + if ( $time < $start ) { $s = SEC_PER_DAY - $start; } else { - $s = SEC_PER_DAY - $offset; + $s = SEC_PER_DAY - $time; + } + } + } + + return $s; +} + +# +# this will return number of seconds that service is available if passed +# downtime of service +# + +sub downtime { + my $self = shift; + + my $time = shift || croak "need downtime timestamp to calculate uptime"; + + # calculate offset -- that is number of seconds since midnight + my @lt = localtime($time); + + # check if day falls into dayMask + return 0 if (! $self->_dayOk($lt[6]) ); + + my $s=0; + + my $start = $self->_start($time); + my $end = $self->_end($time); + + print STDERR "start: $start end: $end time: $time [$lt[2]:$lt[1]:$lt[0]]\n" if ($debug); + + if ( $end > $start ) { + if ($time > $start && $time <= $end) { + $s = $end - $time; + } elsif ($time < $start) { + $s = $end - $start; + } + } elsif ( $start > $end ) { # over midnight + if ( $time < $end ) { + if ( $time < $start) { + $s = $time; + } else { + $s = 0; + } + } else { + if ( $time < $start ) { + $s = SEC_PER_DAY - $end; + } else { + $s = SEC_PER_DAY - $end + $start - $time; } } } @@ -176,9 +265,10 @@ # sub fmt_interval { - my $s = shift || 0; + my $int = shift || 0; my $out = ""; + my $s=$int; my $d = int($s/(24*60*60)); $s = $s % (24*60*60); my $h = int($s/(60*60)); @@ -188,11 +278,84 @@ $out .= $d."d " if ($d > 0); - $out .= sprintf("%02d:%02d:%02d",$h,$m,$s); + if ($debug) { + $out .= sprintf("%02d:%02d:%02d [%d]",$h,$m,$s, $int); + } else { + $out .= sprintf("%02d:%02d:%02d",$h,$m,$s); + } return $out; } +# +# this function will calculate uptime for some interval +# + +sub interval { + my $self = shift; + my $from = shift || croak "need start time for interval"; + my $to = shift || croak "need end time for interval"; + + print STDERR "from:\t$from\t",scalar localtime($from),"\n" if ($debug); + print STDERR "to:\t$to\t",scalar localtime($to),"\n" if ($debug); + + my $total = 0; + + # calc first day availability + print STDERR "t:\t$from\t",scalar localtime($from),"\n" if ($debug); + $total += $self->uptime($from); + + print STDERR "total: ",fmt_interval($total)," (first)\n" if ($debug); + + # add all whole days + + my $sec_in_day = $self->{sec_in_interval}; + my $day = 86400; # 24*60*60 + + my $loop_start_time = int($from/$day)*$day + $day; + my $loop_end_time = int($to/$day)*$day; + + print STDERR "loop (start - end): $loop_start_time - $loop_end_time\n" if ($debug); + + for (my $t = $loop_start_time; $t < $loop_end_time; $t += $day) { + print STDERR "t:\t$t\t",scalar localtime($t),"\n" if ($debug); + $total += $sec_in_day if ($self->day_in_interval($t)); + print STDERR "total: ",fmt_interval($total)," (loop)\n" if ($debug); + } + + # add rest of last day + print STDERR "t:\t$to\t",scalar localtime($to),"\n" if ($debug); + + if ($to > $self->_start($to)) { + if ($to <= $self->_end($to)) { + $total = abs($total - $self->downtime($to)); + } elsif($self->day_in_interval($to) && $loop_start_time < $loop_end_time) { + $total += $sec_in_day; + } + } + print STDERR "total: ",fmt_interval($total)," (final)\n" if ($debug); + + return $total; +} + +# +# this function will check if day falls into interval +# + +sub day_in_interval { + my $self = shift; + + my $time = shift || croak "need timestamp to check if day is in interval"; + + my @lt = localtime($time); + return $self->_dayOk($lt[6]); +} + +# +# return seconds in defined interval +# + + 1; __END__ @@ -239,34 +402,34 @@ =over 4 =item * -Time::Avail::DAY_MONDAY +Time::Available::DAY_MONDAY =item * -Time::Avail::DAY_TUESDAY +Time::Available::DAY_TUESDAY =item * -Time::Avail::DAY_WEDNESDAY +Time::Available::DAY_WEDNESDAY =item * -Time::Avail::DAY_THURSDAY +Time::Available::DAY_THURSDAY =item * -Time::Avail::DAY_FRIDAY +Time::Available::DAY_FRIDAY =item * -Time::Avail::DAY_SATURDAY +Time::Available::DAY_SATURDAY =item * -Time::Avail::DAY_SUNDAY +Time::Available::DAY_SUNDAY =item * -Time::Avail::DAY_WEEKDAY +Time::Available::DAY_WEEKDAY =item * -Time::Avail::DAY_WEEKEND +Time::Available::DAY_WEEKEND =item * -Time::Avail::DAY_EVERYDAY +Time::Available::DAY_EVERYDAY =back @@ -299,9 +462,6 @@ =over 8 =item * -Use croak and not die in module for better error handling - -=item * Allow arbitary (array?) of holidays to be included. =back