Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Tests legacy Moodle date/time functions.
  19   *
  20   * @package   core
  21   * @copyright 2015 Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
  22   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   * @author    Petr Skoda <petr.skoda@totaralms.com>
  24   */
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  /**
  29   * Tests legacy Moodle date/time functions.
  30   *
  31   * @package   core
  32   * @copyright 2015 Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
  33   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  34   * @author    Petr Skoda <petr.skoda@totaralms.com>
  35   */
  36  class core_date_legacy_testcase extends advanced_testcase {
  37      public function test_settings() {
  38          global $CFG;
  39          $this->resetAfterTest();
  40  
  41          $this->assertNotEmpty($CFG->timezone);
  42  
  43          $this->assertSame('99', $CFG->forcetimezone);
  44  
  45          $user = $this->getDataGenerator()->create_user();
  46          $this->assertSame('99', $user->timezone);
  47      }
  48  
  49      public function test_get_user_timezone() {
  50          global $CFG, $USER;
  51  
  52          $this->resetAfterTest();
  53  
  54          $user = $this->getDataGenerator()->create_user();
  55          $this->setUser($user);
  56  
  57          // All set to something.
  58  
  59          $this->setTimezone('Pacific/Auckland', 'Pacific/Auckland');
  60          $USER->timezone = 'Europe/Prague';
  61  
  62          $tz = get_user_timezone();
  63          $this->assertSame('Europe/Prague', $tz);
  64  
  65          $tz = get_user_timezone(99);
  66          $this->assertSame('Europe/Prague', $tz);
  67          $tz = get_user_timezone('99');
  68          $this->assertSame('Europe/Prague', $tz);
  69  
  70          $tz = get_user_timezone('Europe/Berlin');
  71          $this->assertSame('Europe/Berlin', $tz);
  72  
  73          // User timezone not set.
  74  
  75          $this->setTimezone('Pacific/Auckland', 'Pacific/Auckland');
  76          $USER->timezone = '99';
  77  
  78          $tz = get_user_timezone();
  79          $this->assertSame('Pacific/Auckland', $tz);
  80  
  81          $tz = get_user_timezone(99);
  82          $this->assertSame('Pacific/Auckland', $tz);
  83          $tz = get_user_timezone('99');
  84          $this->assertSame('Pacific/Auckland', $tz);
  85  
  86          $tz = get_user_timezone('Europe/Berlin');
  87          $this->assertSame('Europe/Berlin', $tz);
  88  
  89          // Server timezone not set.
  90  
  91          $this->setTimezone('99', 'Pacific/Auckland');
  92          $USER->timezone = 'Europe/Prague';
  93  
  94          $tz = get_user_timezone();
  95          $this->assertSame('Europe/Prague', $tz);
  96  
  97          $tz = get_user_timezone(99);
  98          $this->assertSame('Europe/Prague', $tz);
  99          $tz = get_user_timezone('99');
 100          $this->assertSame('Europe/Prague', $tz);
 101  
 102          $tz = get_user_timezone('Europe/Berlin');
 103          $this->assertSame('Europe/Berlin', $tz);
 104  
 105          // Server and user timezone not set.
 106  
 107          $this->setTimezone('99', 'Pacific/Auckland');
 108          $USER->timezone = '99';
 109  
 110          $tz = get_user_timezone();
 111          $this->assertSame(99.0, $tz);
 112  
 113          $tz = get_user_timezone(99);
 114          $this->assertSame(99.0, $tz);
 115          $tz = get_user_timezone('99');
 116          $this->assertSame(99.0, $tz);
 117  
 118          $tz = get_user_timezone('Europe/Berlin');
 119          $this->assertSame('Europe/Berlin', $tz);
 120      }
 121  
 122      public function test_dst_offset_on() {
 123          $time = gmmktime(1, 1, 1, 3, 1, 2015);
 124          $this->assertSame(3600, dst_offset_on($time, 'Pacific/Auckland'));
 125          $this->assertSame(0, dst_offset_on($time, 'Australia/Perth'));
 126          $this->assertSame(1800, dst_offset_on($time, 'Australia/Lord_Howe'));
 127          $this->assertSame(0, dst_offset_on($time, 'Europe/Prague'));
 128          $this->assertSame(0, dst_offset_on($time, 'America/New_York'));
 129  
 130          $time = gmmktime(1, 1, 1, 5, 1, 2015);
 131          $this->assertSame(0, dst_offset_on($time, 'Pacific/Auckland'));
 132          $this->assertSame(0, dst_offset_on($time, 'Australia/Perth'));
 133          $this->assertSame(0, dst_offset_on($time, 'Australia/Lord_Howe'));
 134          $this->assertSame(3600, dst_offset_on($time, 'Europe/Prague'));
 135          $this->assertSame(3600, dst_offset_on($time, 'America/New_York'));
 136      }
 137  
 138      public function test_make_timestamp() {
 139          global $CFG;
 140  
 141          $this->resetAfterTest();
 142  
 143          // There are quite a lot of problems, let's pick some less problematic zones for now.
 144          $timezones = array('Europe/Prague', 'Europe/London', 'Australia/Perth', 'Pacific/Auckland', 'America/New_York', '99');
 145  
 146          $dates = array(
 147              array(2, 1, 0, 40, 40),
 148              array(4, 3, 0, 30, 22),
 149              array(9, 5, 0, 20, 19),
 150              array(11, 28, 0, 10, 45),
 151          );
 152          $years = array(1999, 2009, 2014, 2018);
 153  
 154          $this->setTimezone('Pacific/Auckland', 'Pacific/Auckland');
 155          foreach ($timezones as $tz) {
 156              foreach ($years as $year) {
 157                  foreach ($dates as $date) {
 158                      $result = make_timestamp($year, $date[0], $date[1], $date[2], $date[3], $date[4], $tz, true);
 159                      $expected = new DateTime('now', new DateTimeZone(($tz == 99 ? 'Pacific/Auckland' : $tz)));
 160                      $expected->setDate($year, $date[0], $date[1]);
 161                      $expected->setTime($date[2], $date[3], $date[4]);
 162                      $this->assertSame($expected->getTimestamp(), $result,
 163                          'Incorrect result for data ' . $expected->format("D, d M Y H:i:s O") . ' ' . $tz);
 164                  }
 165              }
 166          }
 167  
 168          $this->setTimezone('99', 'Pacific/Auckland');
 169          foreach ($timezones as $tz) {
 170              foreach ($years as $year) {
 171                  foreach ($dates as $date) {
 172                      $result = make_timestamp($year, $date[0], $date[1], $date[2], $date[3], $date[4], $tz, true);
 173                      $expected = new DateTime('now', new DateTimeZone(($tz == 99 ? 'Pacific/Auckland' : $tz)));
 174                      $expected->setDate($year, $date[0], $date[1]);
 175                      $expected->setTime($date[2], $date[3], $date[4]);
 176                      $this->assertSame($expected->getTimestamp(), $result,
 177                          'Incorrect result for data ' . $expected->format("D, d M Y H:i:s O") . ' ' . $tz);
 178                  }
 179              }
 180          }
 181      }
 182  
 183      public function test_usergetdate() {
 184          global $CFG;
 185  
 186          $this->resetAfterTest();
 187  
 188          // There are quite a lot of problems, let's pick some less problematic zones for now.
 189          $timezones = array('Europe/Prague', 'Europe/London', 'Australia/Perth', 'Pacific/Auckland', 'America/New_York', '99');
 190  
 191          $dates = array(
 192              array(2, 1, 0, 40, 40),
 193              array(4, 3, 0, 30, 22),
 194              array(9, 5, 0, 20, 19),
 195              array(11, 28, 0, 10, 45),
 196          );
 197          $years = array(1999, 2009, 2014, 2018);
 198  
 199          $this->setTimezone('Pacific/Auckland', 'Pacific/Auckland');
 200          foreach ($timezones as $tz) {
 201              foreach ($years as $year) {
 202                  foreach ($dates as $date) {
 203                      $expected = new DateTime('now', new DateTimeZone(($tz == 99 ? 'Pacific/Auckland' : $tz)));
 204                      $expected->setDate($year, $date[0], $date[1]);
 205                      $expected->setTime($date[2], $date[3], $date[4]);
 206                      $result = usergetdate($expected->getTimestamp(), $tz);
 207                      unset($result[0]); // Extra introduced by getdate().
 208                      $ex = array(
 209                          'seconds' => $date[4],
 210                          'minutes' => $date[3],
 211                          'hours' => $date[2],
 212                          'mday' => $date[1],
 213                          'wday' => (int)$expected->format('w'),
 214                          'mon' => $date[0],
 215                          'year' => $year,
 216                          'yday' => (int)$expected->format('z'),
 217                          'weekday' => $expected->format('l'),
 218                          'month' => $expected->format('F'),
 219                      );
 220                      $this->assertSame($ex, $result,
 221                          'Incorrect result for data ' . $expected->format("D, d M Y H:i:s O") . ' ' . $tz);
 222                  }
 223              }
 224          }
 225  
 226          $this->setTimezone('99', 'Pacific/Auckland');
 227          foreach ($timezones as $tz) {
 228              foreach ($years as $year) {
 229                  foreach ($dates as $date) {
 230                      $expected = new DateTime('now', new DateTimeZone(($tz == 99 ? 'Pacific/Auckland' : $tz)));
 231                      $expected->setDate($year, $date[0], $date[1]);
 232                      $expected->setTime($date[2], $date[3], $date[4]);
 233                      $result = usergetdate($expected->getTimestamp(), $tz);
 234                      unset($result[0]); // Extra introduced by getdate().
 235                      $ex = array(
 236                          'seconds' => $date[4],
 237                          'minutes' => $date[3],
 238                          'hours' => $date[2],
 239                          'mday' => $date[1],
 240                          'wday' => (int)$expected->format('w'),
 241                          'mon' => $date[0],
 242                          'year' => $year,
 243                          'yday' => (int)$expected->format('z'),
 244                          'weekday' => $expected->format('l'),
 245                          'month' => $expected->format('F'),
 246                      );
 247                      $this->assertSame($ex, $result,
 248                          'Incorrect result for data ' . $expected->format("D, d M Y H:i:s O") . ' ' . $tz);
 249                  }
 250              }
 251          }
 252      }
 253  
 254      public function test_userdate() {
 255          global $CFG;
 256  
 257          $this->resetAfterTest();
 258  
 259          $dates = array(
 260              array(2, 1, 0, 40, 40),
 261              array(4, 3, 0, 30, 22),
 262              array(9, 5, 0, 20, 19),
 263              array(11, 28, 0, 10, 45),
 264          );
 265          $years = array(1999, 2009, 2014, 2018);
 266  
 267          $users = array();
 268          $users[] = $this->getDataGenerator()->create_user(array('timezone' => 99));
 269          $users[] = $this->getDataGenerator()->create_user(array('timezone' => 'Europe/Prague'));
 270          $users[] = $this->getDataGenerator()->create_user(array('timezone' => 'Pacific/Auckland'));
 271          $users[] = $this->getDataGenerator()->create_user(array('timezone' => 'Australia/Perth'));
 272          $users[] = $this->getDataGenerator()->create_user(array('timezone' => 'America/New_York'));
 273  
 274          $format = get_string('strftimedaydatetime', 'langconfig');
 275  
 276          $this->setTimezone('Pacific/Auckland', 'Pacific/Auckland');
 277          foreach ($years as $year) {
 278              foreach ($dates as $date) {
 279                  $expected = new DateTime('now', new DateTimeZone('UTC'));
 280                  $expected->setDate($year, $date[0], $date[1]);
 281                  $expected->setTime($date[2], $date[3], $date[4]);
 282  
 283                  foreach ($users as $user) {
 284                      $this->setUser($user);
 285                      $expected->setTimezone(new DateTimeZone(($user->timezone == 99 ? 'Pacific/Auckland' : $user->timezone)));
 286                      $result = userdate($expected->getTimestamp(), '', 99, false, false);
 287                      date_default_timezone_set($expected->getTimezone()->getName());
 288                      $ex = strftime($format, $expected->getTimestamp());
 289                      date_default_timezone_set($CFG->timezone);
 290                      $this->assertSame($ex, $result);
 291                  }
 292              }
 293          }
 294      }
 295  
 296      public function test_usertime() {
 297          // This is a useless bad hack, it needs to be completely eliminated.
 298  
 299          $time = gmmktime(1, 1, 1, 3, 1, 2015);
 300          $this->assertSame($time - (60 * 60 * 1), usertime($time, '1'));
 301          $this->assertSame($time - (60 * 60 * -1), usertime($time, '-1'));
 302          $this->assertSame($time - (60 * 60 * 1), usertime($time, 'Europe/Prague'));
 303          $this->assertSame($time - (60 * 60 * 8), usertime($time, 'Australia/Perth'));
 304          $this->assertSame($time - (60 * 60 * 12), usertime($time, 'Pacific/Auckland'));
 305          $this->assertSame($time - (60 * 60 * -5), usertime($time, 'America/New_York'));
 306  
 307          $time = gmmktime(1, 1, 1, 5, 1, 2015);
 308          $this->assertSame($time - (60 * 60 * 1), usertime($time, '1'));
 309          $this->assertSame($time - (60 * 60 * -1), usertime($time, '-1'));
 310          $this->assertSame($time - (60 * 60 * 1), usertime($time, 'Europe/Prague'));
 311          $this->assertSame($time - (60 * 60 * 8), usertime($time, 'Australia/Perth'));
 312          $this->assertSame($time - (60 * 60 * 12), usertime($time, 'Pacific/Auckland'));
 313          $this->assertSame($time - (60 * 60 * -5), usertime($time, 'America/New_York'));
 314      }
 315  
 316      public function test_usertimezone() {
 317          global $USER;
 318          $this->resetAfterTest();
 319  
 320          $this->setTimezone('Pacific/Auckland', 'Pacific/Auckland');
 321  
 322          $USER->timezone = 'Europe/Prague';
 323          $this->assertSame('Europe/Prague', usertimezone());
 324  
 325          $USER->timezone = '1';
 326          $this->assertSame('UTC+1', usertimezone());
 327  
 328          $USER->timezone = '0';
 329          $this->assertSame('UTC', usertimezone());
 330  
 331          $USER->timezone = '99';
 332          $this->assertSame('Pacific/Auckland', usertimezone());
 333  
 334          $USER->timezone = '99';
 335          $this->assertSame('Europe/Berlin', usertimezone('Europe/Berlin'));
 336  
 337          $USER->timezone = '99';
 338          $this->assertSame('Pacific/Auckland', usertimezone('99'));
 339  
 340          $USER->timezone = 'Europe/Prague';
 341          $this->assertSame('Europe/Prague', usertimezone('99'));
 342  
 343          // When passed an unknown non-whole hour TZ, verify we round to closest
 344          // hour. (Possible for legacy reasons when old timezones go away).
 345          $USER->timezone = '-9.23';
 346          $this->assertSame('UTC-9', usertimezone('99'));
 347      }
 348  }