diff --git a/reportbuilder/classes/local/filters/date.php b/reportbuilder/classes/local/filters/date.php index 3cc89219885..696625b1201 100644 --- a/reportbuilder/classes/local/filters/date.php +++ b/reportbuilder/classes/local/filters/date.php @@ -243,8 +243,18 @@ class date extends base { break; case self::DATE_UNIT_WEEK: if ($operator === self::DATE_CURRENT) { - $datestart = $datestart->modify('monday this week')->setTime(0, 0); - $dateend = $dateend->modify('sunday this week')->setTime(23, 59, 59); + // The first day of the week is determined by site calendar configuration/preferences. + $startweekday = \core_calendar\type_factory::get_calendar_instance()->get_starting_weekday(); + $weekdays = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']; + + // If calculated start of week is after today (today is Tues/start of week is Weds), move back a week. + $datestartnow = $datestart->getTimestamp(); + $datestart = $datestart->modify($weekdays[$startweekday] . ' this week')->setTime(0, 0); + if ($datestart->getTimestamp() > $datestartnow) { + $datestart = $datestart->modify('-1 week'); + } + + $dateend = $datestart->modify('+6 day')->setTime(23, 59, 59); } else if ($operator === self::DATE_LAST) { $datestart = $datestart->modify("-{$dateunitvalue} week"); } else if ($operator === self::DATE_NEXT) { diff --git a/reportbuilder/tests/local/filters/date_test.php b/reportbuilder/tests/local/filters/date_test.php index d35a3baa828..606c9db3e2c 100644 --- a/reportbuilder/tests/local/filters/date_test.php +++ b/reportbuilder/tests/local/filters/date_test.php @@ -115,6 +115,105 @@ class date_test extends advanced_testcase { $this->assertEquals([$usertwo->username], $usernames); } + /** + * Data provider for {@see test_get_sql_filter_current_week} + * + * @return array + */ + public function get_sql_filter_current_week_provider(): array { + return array_map(static function(int $day): array { + return [$day]; + }, range(0, 6)); + } + + /** + * Test getting filter SQL for the current week. Note that relative dates are hard to test, here we are asserting that + * the current time is always within the current week regardless of calendar configuration/preferences + * + * @param int $startweekday + * + * @dataProvider get_sql_filter_current_week_provider + */ + public function test_get_sql_filter_current_week(int $startweekday): void { + global $DB; + + $this->resetAfterTest(); + + set_config('calendar_startwday', $startweekday); + + $user = $this->getDataGenerator()->create_user(['timecreated' => time()]); + + $filter = new filter( + date::class, + 'test', + new lang_string('yes'), + 'testentity', + 'timecreated' + ); + + [$select, $params] = date::create($filter)->get_sql_filter([ + $filter->get_unique_identifier() . '_operator' => date::DATE_CURRENT, + $filter->get_unique_identifier() . '_unit' => date::DATE_UNIT_WEEK, + ]); + + $matchingusers = $DB->get_fieldset_select('user', 'username', $select, $params); + $this->assertContains($user->username, $matchingusers); + } + + /** + * Data provider for {@see test_get_sql_filter_current_week_no_match} + * + * @return array + */ + public function get_sql_filter_current_week_no_match_provider(): array { + $data = []; + + // For each day, create provider data for -/+ 8 days. + foreach (range(0, 6) as $day) { + $data = array_merge($data, [ + [$day, '-8 day'], + [$day, '+8 day'], + ]); + } + + return $data; + } + + /** + * Test getting filter SQL for the current week excludes dates that don't match (outside week time range) + * + * @param int $startweekday + * @param string $timecreated Relative time suitable for passing to {@see strtotime} + * + * @dataProvider get_sql_filter_current_week_no_match_provider + */ + public function test_get_sql_filter_current_week_no_match(int $startweekday, string $timecreated): void { + global $DB; + + $this->resetAfterTest(); + + set_config('calendar_startwday', $startweekday); + + $usertimecreated = strtotime($timecreated); + $user = $this->getDataGenerator()->create_user(['timecreated' => $usertimecreated]); + + $filter = new filter( + date::class, + 'test', + new lang_string('yes'), + 'testentity', + 'timecreated' + ); + + [$select, $params] = date::create($filter)->get_sql_filter([ + $filter->get_unique_identifier() . '_operator' => date::DATE_CURRENT, + $filter->get_unique_identifier() . '_unit' => date::DATE_UNIT_WEEK, + ]); + + $matchingusers = $DB->get_fieldset_select('user', 'username', $select, $params); + $this->assertNotContains($user->username, $matchingusers); + } + /** * Data provider for {@see test_get_sql_filter_relative} * @@ -131,8 +230,8 @@ class date_test extends advanced_testcase { 'Last two months' => [date::DATE_LAST, 2, date::DATE_UNIT_MONTH, '-7 week'], 'Last two years' => [date::DATE_LAST, 2, date::DATE_UNIT_YEAR, '-15 month'], + // Current week is tested separately. 'Current day' => [date::DATE_CURRENT, null, date::DATE_UNIT_DAY], - 'Current week' => [date::DATE_CURRENT, null, date::DATE_UNIT_WEEK], 'Current month' => [date::DATE_CURRENT, null, date::DATE_UNIT_MONTH], 'Current year' => [date::DATE_CURRENT, null, date::DATE_UNIT_YEAR],