Search code examples
phparraysdatemktime

Aggregate when it was certain weeks ago


So I have this situation. I have multiple arrays which are like this:

$array('date'=>'00-00-00', 'value'=>'xx');

What I want to do is go through all the arrays, and make 4 variables: $week1, $week2, $week3, $week4 where I would store the aggregated values depending if it was 1 week ago, 2 weeks ago, 3 weeks ago or 4 weeks ago from a certain date.

What I have tried is this, but it's not working. Even though I have a lot of dates, and they have values, it's returning 0 for everything, the names are just placeholder, I didnt actually call them 'array':

     $date = 'xx-xx-xx';
     $month = array();

     $week1 = strtotime($date . '-1 week');
     $week2 = strtotime($date . '-2 week');
     $week3 = strtotime($date . '-3 week');
     $week4 = strtotime($date . '-4 week');


     foreach($arrays as $array){

        if( (date('W', strtotime($array['date']) == date('W', strtotime($week1)))) AND (date('Y', strtotime($array['date'])) == date('Y', strtotime($week1)))){
            $month['week1'] += $array['value'];
        }

        if( (date('W', strtotime($array['date']) == date('W', strtotime($week2)))) AND (date('Y', strtotime($array['date'])) == date('Y', strtotime($week2)))){
            $month['week2'] += $array['value'];
        }

        if( (date('W', strtotime($array['date']) == date('W', strtotime($week3)))) AND (date('Y', strtotime($array['date'])) == date('Y', strtotime($week3)))){
            $month['week3'] += $array['value'];
        }

        if( (date('W', strtotime($array['date']) == date('W', strtotime($week4)))) AND (date('Y', strtotime($array['date'])) == date('Y', strtotime($week4)))){
            $month['week4'] += $array['value'];
        }           
     }

     return $month;

Solution

  • You have a bit of a problem with your data format in that you are using an ambiguous format of XX-XX-XX. What does that mean? YY-MM-DD? MM-DD-YY? DD-MM-YY? You can't expect strtotime to convert that format without further definition as to what the date string represents.

    I would also suggest use of DateTime, DateInterval, DatePeriod, etc. classes as these are much more full-featured than older PHP date manipulation functions.

    So, I might implement like this:

    $array = array(...); // your input array
    $start_time = new DateTime();
    // Alternately, if you need week boundary to not be based on "now" 
    // but rather on fixed start of week you could do something like
    // $current_time = new DateTime('Monday this week 00:00:00');
    $date_interval = new DateInterval('P1W');
    $date_interval->invert = 1; // make it negative interval
    // build DatePeriod object with 4 interval periods - don't include start date
    $date_period = new DatePeriod($start_time, $date_interval, 4, DatePeriod::EXCLUDE_START_DATE);
    
    $final_array = array(0,0,0,0); // the destination array with default start values
    array_walk($array, function($item, $key_not_used) use ($date_period, $final_array) {
        // change date format as necessary below
        $item_time = DateTime::createFromFormat('y-m-d', $item['date']);
        $value = $item['value'];
        foreach($date_period as $i => $comparison_time) {
            if ($item_time > $comparison_time) {
                // aggregate this value into $final_array.
                // I assume this is simple addition but any sort of aggregation can be used by changing this line below
                $final_array[$i] = $final_array[$i] + $value;
                // break out of loop since comparison already completed
                break;
            }
        }
    });
    var_dump($final_array);
    

    This would give final array with values like:

    Array(
        [0] => ?, // aggregation for dates > 1 week ago
        [1] => ?, // aggregation for dates between 1 and 2 weeks ago
        [2] => ?, // aggregation for dates between 2 and 3 weeks ago
        [3] => ? // aggregation for dates between 3 and 4 weeks ago
    )