Skip to content

Commit

Permalink
refs matomo-org#1486 this should fix the scheduled alerts for month o…
Browse files Browse the repository at this point in the history
…r week run one day too late under circumstances.
  • Loading branch information
tsteur committed Feb 2, 2014
1 parent 426f666 commit 711456d
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 121 deletions.
67 changes: 40 additions & 27 deletions core/ScheduledTime.php
Expand Up @@ -46,6 +46,8 @@ abstract class ScheduledTime
*/
protected $day = 1;

protected $timezone = null;

/**
* @param $period
* @return Daily|Monthly|Weekly
Expand All @@ -69,33 +71,6 @@ static public function getScheduledTimeForPeriod($period)
}
}

/**
* This method takes the websites timezone into consideration when scheduling a task.
* @param int $idSite
* @param string $period Eg 'day', 'week', 'month'
* @return Daily|Monthly|Weekly
* @throws \Exception
* @ignore
*/
static public function getScheduledTimeForSite($idSite, $period)
{
$arbitraryDateInUTC = Date::factory('2011-01-01');
$midnightInSiteTimezone = date(
'H',
Date::factory(
$arbitraryDateInUTC,
Site::getTimezoneFor($idSite)
)->getTimestamp()
);

$hourInUTC = (24 - $midnightInSiteTimezone) % 24;

$schedule = self::getScheduledTimeForPeriod($period);
$schedule->setHour($hourInUTC);

return $schedule;
}

/**
* Returns the system time used by subclasses to compute schedulings.
* This method has been introduced so unit tests can override the current system time.
Expand Down Expand Up @@ -141,6 +116,44 @@ public function setHour($hour)
$this->hour = $hour;
}

/**
* By setting a timezone you make sure the scheduled task will be run at the requested time in the
* given timezone. This is useful for instance in case you want to make sure a task runs at midnight in a website's
* timezone.
*
* @param string $timezone
*/
public function setTimezone($timezone)
{
$this->timezone = $timezone;
}

protected function adjustTimezone($rescheduledTime)
{
if (is_null($this->timezone)) {
return $rescheduledTime;
}

$arbitraryDateInUTC = Date::factory('2011-01-01');
$dateInTimezone = Date::factory($arbitraryDateInUTC, $this->timezone);

$midnightInTimezone = date('H', $dateInTimezone->getTimestamp());
$hoursDifference = (24 - $midnightInTimezone) % 24;

if ($arbitraryDateInUTC->isEarlier($dateInTimezone)) {
$hoursDifference = -1 * $hoursDifference;
}

$rescheduledTime += (3600 * $hoursDifference);

if (Date::now()->getTimestamp() > $rescheduledTime) {
// make sure the rescheduled date is in the future
$rescheduledTime = (24 * 3600) + $rescheduledTime;
}

return $rescheduledTime;
}

/**
* Computes the delta in seconds needed to adjust the rescheduled time to the required hour.
*
Expand Down
1 change: 1 addition & 0 deletions core/ScheduledTime/Daily.php
Expand Up @@ -38,6 +38,7 @@ public function getRescheduledTime()

// Adjusts the scheduled hour
$rescheduledTime = $this->adjustHour($rescheduledTime);
$rescheduledTime = $this->adjustTimezone($rescheduledTime);

return $rescheduledTime;
}
Expand Down
1 change: 1 addition & 0 deletions core/ScheduledTime/Monthly.php
Expand Up @@ -104,6 +104,7 @@ public function getRescheduledTime()

// Adjusts the scheduled hour
$rescheduledTime = $this->adjustHour($rescheduledTime);
$rescheduledTime = $this->adjustTimezone($rescheduledTime);

return $rescheduledTime;
}
Expand Down
1 change: 1 addition & 0 deletions core/ScheduledTime/Weekly.php
Expand Up @@ -49,6 +49,7 @@ public function getRescheduledTime()

// Adjusts the scheduled hour
$rescheduledTime = $this->adjustHour($rescheduledTime);
$rescheduledTime = $this->adjustTimezone($rescheduledTime);

return $rescheduledTime;
}
Expand Down
51 changes: 36 additions & 15 deletions tests/PHPUnit/Core/ScheduledTime/DailyTest.php
Expand Up @@ -87,13 +87,29 @@ public function testGetRescheduledTimeDailyUnspecifiedHour()
* Expected :
* getRescheduledTime returns Saturday January 2 1971 00:00:00 UTC
*/
$mock = $this->getMock('\Piwik\ScheduledTime\Daily', array('getTime'));
$mock->expects($this->any())
->method('getTime')
->will($this->returnValue(self::$_JANUARY_01_1971_09_10_00));
$mock = $this->getDailyMock(self::$_JANUARY_01_1971_09_10_00);
$this->assertEquals(self::$_JANUARY_02_1971_00_00_00, $mock->getRescheduledTime());
}

public function test_setTimezone_ShouldConvertRescheduledTime()
{
$oneHourInSeconds = 3600;

$mock = $this->getDailyMock(self::$_JANUARY_01_1971_09_10_00);
$timeUTC = $mock->getRescheduledTime();
$this->assertEquals(self::$_JANUARY_02_1971_00_00_00, $timeUTC);


$mock->setTimezone('Pacific/Auckland');
$timeAuckland = $mock->getRescheduledTime();
$this->assertEquals(-11 * $oneHourInSeconds, $timeAuckland - $timeUTC);


$mock->setTimezone('America/Los_Angeles');
$timeLosAngeles = $mock->getRescheduledTime();
$this->assertEquals(8 * $oneHourInSeconds, $timeLosAngeles - $timeUTC);
}

/**
* Tests getRescheduledTime on Daily with specified hour
* @group Core
Expand All @@ -110,10 +126,7 @@ public function testGetRescheduledTimeDailySpecifiedHour()
* Expected :
* getRescheduledTime returns Saturday January 2 1971 09:00:00 UTC
*/
$mock = $this->getMock('\Piwik\ScheduledTime\Daily', array('getTime'));
$mock->expects($this->any())
->method('getTime')
->will($this->returnValue(self::$_JANUARY_01_1971_09_00_00));
$mock = $this->getDailyMock(self::$_JANUARY_01_1971_09_00_00);
$mock->setHour(9);
$this->assertEquals(self::$_JANUARY_02_1971_09_00_00, $mock->getRescheduledTime());

Expand All @@ -127,10 +140,8 @@ public function testGetRescheduledTimeDailySpecifiedHour()
* Expected :
* getRescheduledTime returns Saturday January 2 1971 09:00:00 UTC
*/
$mock = $this->getMock('\Piwik\ScheduledTime\Daily', array('getTime'));
$mock->expects($this->any())
->method('getTime')
->will($this->returnValue(self::$_JANUARY_01_1971_12_10_00));

$mock = $this->getDailyMock(self::$_JANUARY_01_1971_12_10_00);
$mock->setHour(9);
$this->assertEquals(self::$_JANUARY_02_1971_09_00_00, $mock->getRescheduledTime());

Expand All @@ -144,11 +155,21 @@ public function testGetRescheduledTimeDailySpecifiedHour()
* Expected :
* getRescheduledTime returns Saturday January 2 1971 00:00:00 UTC
*/
$mock = $this->getDailyMock(self::$_JANUARY_01_1971_12_10_00);
$mock->setHour(0);
$this->assertEquals(self::$_JANUARY_02_1971_00_00_00, $mock->getRescheduledTime());
}

/**
* @param $currentTime
* @return \Piwik\ScheduledTime\Daily
*/
private function getDailyMock($currentTime)
{
$mock = $this->getMock('\Piwik\ScheduledTime\Daily', array('getTime'));
$mock->expects($this->any())
->method('getTime')
->will($this->returnValue(self::$_JANUARY_01_1971_12_10_00));
$mock->setHour(0);
$this->assertEquals(self::$_JANUARY_02_1971_00_00_00, $mock->getRescheduledTime());
->will($this->returnValue($currentTime));
return $mock;
}
}

0 comments on commit 711456d

Please sign in to comment.