From 2e0bb2af8b7f090d4f6c0f588e0db746477ff578 Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Thu, 7 Feb 2013 11:11:05 +0800 Subject: [PATCH 1/2] MDL-36380 stats: No more duplicated entries when viewing monthly stats --- lib/statslib.php | 53 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/lib/statslib.php b/lib/statslib.php index 3582c018a93..5218444b78e 100644 --- a/lib/statslib.php +++ b/lib/statslib.php @@ -1442,6 +1442,18 @@ function stats_get_report_options($courseid,$mode) { return $reportoptions; } +/** + * Fix missing entries in the statistics. + * + * This creates a dummy stat when nothing happened during a day/week/month. + * + * @param array $stats array of statistics. + * @param int $timeafter unused. + * @param string $timestr type of statistics to generate (dayly, weekly, monthly). + * @param boolean $line2 + * @param boolean $line3 + * @return array of fixed statistics. + */ function stats_fix_zeros($stats,$timeafter,$timestr,$line2=true,$line3=false) { if (empty($stats)) { @@ -1449,23 +1461,29 @@ function stats_fix_zeros($stats,$timeafter,$timestr,$line2=true,$line3=false) { } $timestr = str_replace('user_','',$timestr); // just in case. - $fun = 'stats_get_base_'.$timestr; + // Gets the current user base time. + $fun = 'stats_get_base_'.$timestr; $now = $fun(); - $times = array(); - // add something to timeafter since it is our absolute base + // Extract the ending time of the statistics. $actualtimes = array(); - foreach ($stats as $statid=>$s) { - //normalize the times in stats - those might have been created in different timezone, DST etc. - $s->timeend = $fun($s->timeend + 60*60*5); + foreach ($stats as $statid => $s) { + // Normalise the month date to the 1st if for any reason it's set to later. But we ignore + // anything above or equal to 29 because sometimes we get the end of the month. + if ($timestr == 'monthly' && date('d', $s->timeend) > 1 && date('d', $s->timeend) < 29) { + $s->timeend = mktime(date('H', $s->timeend), date('i', $s->timeend), date('s', $s->timeend), + date('m', $s->timeend), 1, date('Y', $s->timeend)); + } $stats[$statid] = $s; - $actualtimes[] = $s->timeend; } - $timeafter = array_pop(array_values($actualtimes)); + $actualtimesvalues = array_values($actualtimes); + $timeafter = array_pop($actualtimesvalues); + // Generate a base timestamp for each possible month/week/day. + $times = array(); while ($timeafter < $now) { $times[] = $timeafter; if ($timestr == 'daily') { @@ -1473,12 +1491,26 @@ function stats_fix_zeros($stats,$timeafter,$timestr,$line2=true,$line3=false) { } else if ($timestr == 'weekly') { $timeafter = stats_get_next_week_start($timeafter); } else if ($timestr == 'monthly') { - $timeafter = stats_get_next_month_start($timeafter); + // We can't just simply +1 month because the 31st Jan + 1 month = 2nd of March. + $year = date('Y', $timeafter); + $month = date('m', $timeafter); + $day = date('d', $timeafter); + $dayofnextmonth = $day; + if ($day >= 29) { + $daysinmonth = date('n', mktime(0, 0, 0, $month+1, 1, $year)); + if ($day > $daysinmonth) { + $dayofnextmonth = $daysinmonth; + } + } + $timeafter = mktime(date('H', $timeafter), date('i', $timeafter), date('s', $timeafter), $month+1, + $dayofnextmonth, $year); } else { - return $stats; // this will put us in a never ending loop. + // This will put us in a never ending loop. + return $stats; } } + // Add the base timestamp to the statistics if not present. foreach ($times as $count => $time) { if (!in_array($time,$actualtimes) && $count != count($times) -1) { $newobj = new StdClass; @@ -1499,7 +1531,6 @@ function stats_fix_zeros($stats,$timeafter,$timestr,$line2=true,$line3=false) { usort($stats,"stats_compare_times"); return $stats; - } // helper function to sort arrays by $obj->timeend From bed828de915d4fdc427d40f4b1ca19ed72099ff7 Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Thu, 28 Feb 2013 13:44:42 +0800 Subject: [PATCH 2/2] MDL-36380 stats: Issue with DST and monthly statistics --- lib/statslib.php | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/statslib.php b/lib/statslib.php index 5218444b78e..0cbf77f0c80 100644 --- a/lib/statslib.php +++ b/lib/statslib.php @@ -1468,12 +1468,20 @@ function stats_fix_zeros($stats,$timeafter,$timestr,$line2=true,$line3=false) { // Extract the ending time of the statistics. $actualtimes = array(); + $actualtimeshour = null; foreach ($stats as $statid => $s) { // Normalise the month date to the 1st if for any reason it's set to later. But we ignore - // anything above or equal to 29 because sometimes we get the end of the month. - if ($timestr == 'monthly' && date('d', $s->timeend) > 1 && date('d', $s->timeend) < 29) { - $s->timeend = mktime(date('H', $s->timeend), date('i', $s->timeend), date('s', $s->timeend), - date('m', $s->timeend), 1, date('Y', $s->timeend)); + // anything above or equal to 29 because sometimes we get the end of the month. Also, we will + // set the hours of the result to all of them, that way we prevent DST differences. + if ($timestr == 'monthly') { + $day = date('d', $s->timeend); + if (date('d', $s->timeend) > 1 && date('d', $s->timeend) < 29) { + $day = 1; + } + if (is_null($actualtimeshour)) { + $actualtimeshour = date('H', $s->timeend); + } + $s->timeend = mktime($actualtimeshour, 0, 0, date('m', $s->timeend), $day, date('Y', $s->timeend)); } $stats[$statid] = $s; $actualtimes[] = $s->timeend; @@ -1502,8 +1510,7 @@ function stats_fix_zeros($stats,$timeafter,$timestr,$line2=true,$line3=false) { $dayofnextmonth = $daysinmonth; } } - $timeafter = mktime(date('H', $timeafter), date('i', $timeafter), date('s', $timeafter), $month+1, - $dayofnextmonth, $year); + $timeafter = mktime($actualtimeshour, 0, 0, $month+1, $dayofnextmonth, $year); } else { // This will put us in a never ending loop. return $stats;