Refactorization: moved computation of ticks into function get_ticks.

This commit is contained in:
hjp 2006-09-30 11:45:21 +00:00
parent 464d8c4233
commit 3d0b7f7cbe
1 changed files with 146 additions and 184 deletions

View File

@ -1,3 +1,5 @@
#!/usr/bin/perl
package TimeSeries;
=head1 NAME
@ -21,13 +23,16 @@ implemented.
=cut
use warnings;
use strict;
use File::Temp qw(tempfile);
use Time::Local;
use Data::Dumper;
use HTTP::Date qw(parse_date);
use Time::Local qw(timegm_nocheck);
$VERSION = do { my @r=(q$Revision: 1.15 $=~/\d+/g);sprintf "%d."."%02d"x$#r,@r};
our $VERSION = do { my @r=(q$Revision: 1.16 $=~/\d+/g);sprintf "%d."."%02d"x$#r,@r};
=head2 new(%opts)
@ -291,7 +296,7 @@ sub dstcorr {
my ($time, $period) = @_;
$period = 24 * 3600 unless ($period);
($sec,$min,$hour,$mday,$mon,$year) = localtime($time);
my ($sec,$min,$hour,$mday,$mon,$year) = localtime($time);
my $toff = ($hour * 3600 + $min * 60 * $sec) % $period;
if ($toff != 0) {
if ($toff > $period/2) {
@ -351,197 +356,22 @@ sub plot {
print $ctlfh "set key $self->{legend_position}\n" if ($self->{legend_position});
print $ctlfh "set datafile missing '?'\n";
# compute ticks
# The spacing of the ticks a bit tricky: They should be related to
# common time units (1 hour, 1 day, 1 week, ...), which are
# irregular and not even of constant length (a day can be 23, 24 or
# 25 hours, a month 28 to 31 days, a year 365 or 366 days). Also the
# spacing shouldn't be too tight or too sparse. So there's quite a
# bit of special-case code below (but also much code duplication
# which should be cleaned up).
my $firsttime = $self->{data}[0][0];
my $lasttime = $self->{data}[$#{$self->{data}}][0];
if ($lasttime - $firsttime > 3 * 365 * 24 * 3600) {
# more than 3 years: 1 tick/year
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($firsttime);
$sec = $min = $hour = 0;
$mday = 1;
$mon = int($mon/3) * 3;
$firsttime = timelocal($sec,$min,$hour,$mday,$mon,$year);
print $ctlfh "set xtics rotate (";
my $comma = 0;
my $time;
for (;;) {
$time = timelocal($sec,$min,$hour,$mday,$mon,$year);
if ($comma) {
print $ctlfh ", ";
} else {
$comma = 1;
}
printf $ctlfh qq|"%04d-%02d-%02d" %d|, $year+1900, $mon+1, $mday, $time;
$mon += 3;
if ($mon >= 12) {
$mon -= 12; $year++;
}
if ($time > $lasttime) {last}
}
$lasttime = $time;
print $ctlfh ")\n";
} elsif ($lasttime - $firsttime > 3 * 30 * 24 * 3600) {
# 3 to 36 months: 1 tick/month
my @tics = get_ticks($firsttime, $lasttime);
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($firsttime);
$sec = $min = $hour = 0;
$mday = 1;
$firsttime = timelocal($sec,$min,$hour,$mday,$mon,$year);
print $ctlfh "set xtics rotate (";
my $comma = 0;
my $time;
for (;;) {
$time = timelocal($sec,$min,$hour,$mday,$mon,$year);
if ($comma) {
print $ctlfh ", ";
} else {
$comma = 1;
}
printf $ctlfh qq|"%04d-%02d-%02d" %d|, $year+1900, $mon+1, $mday, $time;
if (++$mon >= 12) {
$mon = 0; $year++;
}
if ($time > $lasttime) {last}
}
$lasttime = $time;
print $ctlfh ")\n";
} elsif ($lasttime - $firsttime > 30 * 24 * 3600) {
# 30 ... 90 days: 1 tick/week.
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($firsttime);
$firsttime -= 86400 * $wday;
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($firsttime);
$sec = $min = $hour = 0;
my $time = $firsttime = timelocal($sec,$min,$hour,$mday,$mon,$year);
print $ctlfh "set xtics rotate (";
my $comma = 0;
for (;;) {
($sec,$min,$hour,$mday,$mon,$year) = localtime($time);
if ($comma) {
print $ctlfh ", ";
} else {
$comma = 1;
}
printf $ctlfh qq|"%04d-%02d-%02d" %d|, $year+1900, $mon+1, $mday, $time;
if ($time > $lasttime) {last}
$time += 7 * 24 * 3600;
$time = dstcorr($time);
}
$lasttime = $time;
print $ctlfh ")\n";
} elsif ($lasttime - $firsttime > 8 * 24 * 3600) {
# 8 .. 30 days: 1 tick per day.
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($firsttime);
$sec = $min = $hour = 0;
my $time = $firsttime = timelocal($sec,$min,$hour,$mday,$mon,$year);
print $ctlfh "set xtics rotate (";
my $comma = 0;
for (;;) {
($sec,$min,$hour,$mday,$mon,$year) = localtime($time);
if ($comma) {
print $ctlfh ", ";
} else {
$comma = 1;
}
printf $ctlfh qq|"%04d-%02d-%02d" %d|, $year+1900, $mon+1, $mday, $time;
if ($time > $lasttime) {last}
$time += 24 * 3600;
$time = dstcorr($time);
}
$lasttime = $time;
print $ctlfh ")\n";
} elsif ($lasttime - $firsttime > 2 * 24 * 3600) {
# 2 .. 8 days: 1 tick/4 hours
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($firsttime);
$sec = $min = $hour = 0;
my $time = $firsttime = timelocal($sec,$min,$hour,$mday,$mon,$year);
print $ctlfh "set xtics rotate (";
my $comma = 0;
for (;;) {
($sec,$min,$hour,$mday,$mon,$year) = localtime($time);
if ($comma) {
print $ctlfh ", ";
} else {
$comma = 1;
}
printf $ctlfh qq|"%04d-%02d-%02d %02d:%02d" %d|, $year+1900, $mon+1, $mday, $hour, $min, $time;
if ($time > $lasttime) {last}
$time += 4 * 3600;
$time = dstcorr($time, 4 * 3600);
}
$lasttime = $time;
print $ctlfh ")\n";
} elsif ($lasttime - $firsttime > 6 * 3600) {
# 6 hours to 2 days: 1 tick per hour.
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($firsttime);
$sec = $min = 0;
my $time = $firsttime = timelocal($sec,$min,$hour,$mday,$mon,$year);
print $ctlfh "set xtics rotate (";
my $comma = 0;
for (;;) {
($sec,$min,$hour,$mday,$mon,$year) = localtime($time);
if ($comma) {
print $ctlfh ", ";
} else {
$comma = 1;
}
printf $ctlfh qq|"%04d-%02d-%02d %02d:%02d" %d|, $year+1900, $mon+1, $mday, $hour, $min, $time;
if ($time > $lasttime) {last}
$time += 3600;
}
$lasttime = $time;
print $ctlfh ")\n";
} else {
# less than 6 hours: 1 tick per minute.
# (ok, that's too much - need to find some intermediate steps,
# but for now I need graphs over a few minutes.
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($firsttime);
$sec = 0;
my $time = $firsttime = timelocal($sec,$min,$hour,$mday,$mon,$year);
print $ctlfh "set xtics rotate (";
my $comma = 0;
for (;;) {
($sec,$min,$hour,$mday,$mon,$year) = localtime($time);
if ($comma) {
print $ctlfh ", ";
} else {
$comma = 1;
}
printf $ctlfh qq|"%04d-%02d-%02d %02d:%02d" %d|, $year+1900, $mon+1, $mday, $hour, $min, $time;
if ($time > $lasttime) {last}
$time += 60;
}
$lasttime = $time;
print $ctlfh ")\n";
}
print $ctlfh "set xtics rotate (",
join(", ", map sprintf(qq|"%s" %d|, $_->[1], $_->[0]), @tics),
")\n";
# what to plot
print $ctlfh "plot ";
$comma = 0;
$col = 2;
my $comma = 0;
my $col = 2;
for $i (@{$self->{legend}}) {
for my $i (@{$self->{legend}}) {
if ($comma) {
print $ctlfh ", ";
} else {
@ -591,4 +421,136 @@ sub plot {
return $graph;
}
=head2 get_ticks($firsttime, $lasttime)
Compute a "reasonable" set of ticks
covering the interval between $firsttime and $lasttime.
The spacing of the ticks a bit tricky: They should be related to
common time units (1 hour, 1 day, 1 week, ...), which are
irregular and not even of constant length (a day can be 23, 24 or
25 hours, a month 28 to 31 days, a year 365 or 366 days). Also the
spacing shouldn't be too tight or too sparse.
The function returns an ordered list of [ $timestamp, $label ] pairs.
$firsttime falls into the interval between the first and second timestamp.
=cut
sub get_ticks {
my ($firsttime, $lasttime) = @_;
my @ticks = ();
if ($lasttime - $firsttime > 3 * 365 * 24 * 3600) {
# more than 3 years: 4 ticks/year
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($firsttime);
$sec = $min = $hour = 0;
$mday = 1;
$mon = int($mon/3) * 3;
$firsttime = timelocal($sec,$min,$hour,$mday,$mon,$year);
my $time;
for (;;) {
$time = timelocal($sec,$min,$hour,$mday,$mon,$year);
push @ticks, [$time, sprintf('%04d-%02d-%02d', $year+1900, $mon+1, $mday)];
$mon += 3;
if ($mon >= 12) {
$mon -= 12; $year++;
}
if ($time > $lasttime) {last}
}
} elsif ($lasttime - $firsttime > 3 * 30 * 24 * 3600) {
# 3 to 36 months: 1 tick/month
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($firsttime);
$sec = $min = $hour = 0;
$mday = 1;
$firsttime = timelocal($sec,$min,$hour,$mday,$mon,$year);
my $time;
for (;;) {
$time = timelocal($sec,$min,$hour,$mday,$mon,$year);
push @ticks, [$time, sprintf('%04d-%02d-%02d', $year+1900, $mon+1, $mday)];
if (++$mon >= 12) {
$mon = 0; $year++;
}
if ($time > $lasttime) {last}
}
} elsif ($lasttime - $firsttime > 30 * 24 * 3600) {
# 30 ... 90 days: 1 tick/week.
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($firsttime);
$firsttime -= 86400 * $wday;
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($firsttime);
$sec = $min = $hour = 0;
my $time = $firsttime = timelocal($sec,$min,$hour,$mday,$mon,$year);
for (;;) {
($sec,$min,$hour,$mday,$mon,$year) = localtime($time);
push @ticks, [$time, sprintf('%04d-%02d-%02d', $year+1900, $mon+1, $mday)];
if ($time > $lasttime) {last}
$time += 7 * 24 * 3600;
$time = dstcorr($time);
}
} elsif ($lasttime - $firsttime > 8 * 24 * 3600) {
# 8 .. 30 days: 1 tick per day.
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($firsttime);
$sec = $min = $hour = 0;
my $time = $firsttime = timelocal($sec,$min,$hour,$mday,$mon,$year);
for (;;) {
($sec,$min,$hour,$mday,$mon,$year) = localtime($time);
push @ticks, [$time, sprintf('%04d-%02d-%02d', $year+1900, $mon+1, $mday)];
if ($time > $lasttime) {last}
$time += 24 * 3600;
$time = dstcorr($time);
}
} elsif ($lasttime - $firsttime > 2 * 24 * 3600) {
# 2 .. 8 days: 1 tick/4 hours
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($firsttime);
$sec = $min = $hour = 0;
my $time = $firsttime = timelocal($sec,$min,$hour,$mday,$mon,$year);
for (;;) {
($sec,$min,$hour,$mday,$mon,$year) = localtime($time);
push @ticks, [$time, sprintf('%04d-%02d-%02d %02d:%02d', $year+1900, $mon+1, $mday, $hour, $min)];
if ($time > $lasttime) {last}
$time += 4 * 3600;
$time = dstcorr($time, 4 * 3600);
}
} elsif ($lasttime - $firsttime > 6 * 3600) {
# 6 hours to 2 days: 1 tick per hour.
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($firsttime);
$sec = $min = 0;
my $time = $firsttime = timelocal($sec,$min,$hour,$mday,$mon,$year);
for (;;) {
($sec,$min,$hour,$mday,$mon,$year) = localtime($time);
push @ticks, [$time, sprintf('%04d-%02d-%02d %02d:%02d', $year+1900, $mon+1, $mday, $hour, $min)];
if ($time > $lasttime) {last}
$time += 3600;
}
} else {
# less than 6 hours: 1 tick per minute.
# (ok, that's too much - need to find some intermediate steps,
# but for now I need graphs over a few minutes.
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($firsttime);
$sec = 0;
my $time = $firsttime = timelocal($sec,$min,$hour,$mday,$mon,$year);
for (;;) {
($sec,$min,$hour,$mday,$mon,$year) = localtime($time);
push @ticks, [$time, sprintf('%04d-%02d-%02d %02d:%02d', $year+1900, $mon+1, $mday, $hour, $min)];
if ($time > $lasttime) {last}
$time += 60;
}
}
return @ticks;
}
1;