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

I've been tasked with providing some high level data. The bosses bosses boss wants to know how we are doing week to week (meeting our SLAs or not). We have to SLAs, one for speed and one for reliability. I've been able to break down the data by day to see if we met either for that day, but having trouble figuring out how to put that into weeks. So say I start with 100% and if one day fails, that figure drops to 80% and then 60% and so on. If we miss it for the whole week then that week gets 0%. Here's a short sample of what I have been able to break down to:
07/16/03 FAILED
07/17/03 PASSED
07/18/03 FAILED
07/21/03 FAILED
07/22/03 FAILED
07/23/03 PASSED
07/24/03 PASSED
07/25/03 PASSED
07/28/03 PASSED
07/29/03 PASSED
07/30/03 PASSED
07/31/03 PASSED
08/01/03 PASSED
Here's the relevant code. I need to somehow in here instead end up with data that looks like this (those dates correspond with mondays)
07/21/03  60
07/28/03  100
08/04/03  80
and so on
open SLA, ">SLA.dat"; foreach $site (@sites) { undef %total; undef %total_time; open INPUT, "<$input_data_directory/$site\.dat" or next; while (<INPUT>) { chomp; $dataline = $_; undef @data; @data = split(/\t/); ($date,$time) = split(/\./,$data[0]); ($hour,$min) = split(/:/,$time); ($mon, $mday, $year) = split(/\//,$date); $timeinseconds = timelocal( 0, 0, 12, $mday, $mon-1, $ +year); $dayOfWeek = (Sun,Mon,Tue,Wed,Thu,Fri,Sat)[(localtime( +$timeinseconds))[6]]; next if (($dayOfWeek eq 'Sun')or($dayOfWeek eq 'Sat')) +; next if (($hour < 8) or ($hour > 19)); $total{$date}++; ### Total number of tests done per da +y shift @data; $total = 0; foreach (@data) { if (($_ eq "0")or($_ eq "0.00")) { $failed{$date}++; } $total+=$_; } $total_time{$date}+=$total; } @keys = sort keys %total; foreach (@keys) { $reliability = (int((($total{$_}-$failed{$_})/$total{$ +_})*100)*100)/100; $average = (int(($total_time{$_}/$total{$_})*100))/100 +; if (($reliability<$reliability{$site})or($average>$spe +ed{$site})) { print SLA "$_\t$site\tFAILED\n"; } else { print SLA "$_\t$site\tPASSED\n"; } } } close SLA;

Replies are listed 'Best First'.
Re: Grouping by week
by Zaxo (Archbishop) on Sep 19, 2003 at 15:25 UTC

    Since you have the dates in localtime list format, you can choose among POSIX::strftime()'s %U, %V, and %W formats to get the week for each date. Using the week number as an index into an array, increment the array element for each 'PASSED' flag you see. To get averages, you'll need to keep track of the total number of entries for a week, too.

    After Compline,
    Zaxo

      This helped a lot. I haven't messed with the POSIX stuff much at all and this is the second time now that it has gotten me through a problem. Guess I really need to do some reading. I now am able to break down my data and display it like this using your advice which is exactly the way I needed it. N/A represents a week where I didn't have 5 days of data. Thanks MUCH.
      27      N/A
      28      60
      29      60
      30      100
      31      100
      32      40
      33      100
      34      80
      35      100
      36      60
      
Re: Grouping by week
by dws (Chancellor) on Sep 19, 2003 at 15:41 UTC
    I've been able to break down the data by day to see if we met either for that day, but having trouble figuring out how to put that into weeks.

    Want the brutal-but-effective way? Don't even try to parse the date. Do a table lookup instead. Precalculate a mapping of date string to week number, and load it into a hash a program startup. Then you can map the date string to a week number quickly, without having to break the date into pieces and do math on them. In the grand scheme of things, there aren't that many dates in a year, so space isn't really an issue.

    Just make sure that the your definition of 'week' matches that the SLA, particularly when a week crosses a year boundary. Occassionally the legal definition gets odd.

Re: Grouping by week
by dragonchild (Archbishop) on Sep 19, 2003 at 15:38 UTC
    Have you looked into Date::Calc or Date::Manip? They provide much of the functionality you're looking for, as well as being able to specify business days and the like.

    ------
    We are the carpenters and bricklayers of the Information Age.

    The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Re: Grouping by week
by sgifford (Prior) on Sep 19, 2003 at 15:52 UTC
    Here's something that will read input like you've given above:
    07/16/03 FAILED
    07/17/03 PASSED
    ...
    
    and summarizes it by week. It should give you an idea of how to modify your program to do what you want.
    #!/usr/bin/perl -w use strict; use Time::Local; my($days,$passed,$firstday,$firstwday); while (<>) { chomp; my($date,$status)=split; my($m,$d,$y) = split(/\//,$date); my($unixtime) = timelocal(0,0,0,$d,$m-1,$y); my(@today)=localtime($unixtime); my $wday = $today[6]; $days++; if ($status eq "PASSED") { $passed++; } if (defined($firstwday)) { if ($wday <= $firstwday) { print $firstday," ",int($passed*100/$days),"\n"; $days=$passed=0; $firstday=$date; $firstwday=$wday; } } else { $firstwday=$wday; $firstday=$date; } } if ($days) { print $firstday," ",int($passed*100/$days),"\n"; }
Re: Grouping by week
by waswas-fng (Curate) on Sep 19, 2003 at 16:02 UTC
    I am sure you know this but 1 day fail is actually 86% success. And even further on that line your SLA states that a partial day fail lets say 85% uptime on monday should count as a 100% day fail over a week time period? That seems very weird to me. Every SLA I have ever dealt with has been % uptime/speed required over a month or week period -- some with different weights for business hour services etc. I am very curious to as how your SLA is worded where your example makes sense.

    -Waswas
      We are only doing Monday through Friday so each day counts as 20%. I average out our response time over a partial day (8am to 8pm) and if that average is less than the SLA or if we had a certain percentage of errors for that partial day than the day fails.
        But that still does not make sense, lets say you fail a day at 20% error rate. this means you are still up 80% of that day which means that the total that should listed as failed for the week would be 5%. under your way of calculating you are stating that it is 20% of a week. Why are you being so hard on yourself? =) also if the SLA is termed monthly that 20% down you had on monday if the only downtime would not be consider a failure of the SLA at all whereas calculating your way could make it a failure for the full term of the month depending on your SLA levels. Also very poor response times for 1 or 2 hours in the morning could scale your whole day as a fail even though the actual "outage" would only be < 10% of the day. seems like you are trying to prove your SLA's are failing to be met to me. =)

        -Waswas