2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
18 * Tests core_date class.
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>
26 defined('MOODLE_INTERNAL') || die();
29 * Tests core_date class.
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>
36 class core_date_testcase extends advanced_testcase {
37 public function test_get_default_php_timezone() {
38 $this->resetAfterTest();
40 $origtz = core_date::get_default_php_timezone();
41 $this->assertNotEmpty($origtz);
43 $this->setTimezone('Pacific/Auckland', 'Europe/Prague');
44 $this->assertSame('Europe/Prague', core_date::get_default_php_timezone());
46 $this->setTimezone('Pacific/Auckland', 'UTC');
47 $this->assertSame('UTC', core_date::get_default_php_timezone());
49 $this->setTimezone('Pacific/Auckland', 'GMT');
50 $this->assertSame('GMT', core_date::get_default_php_timezone());
53 public function test_normalise_timezone() {
54 $this->resetAfterTest();
56 $this->setTimezone('Pacific/Auckland');
57 $this->assertSame('Pacific/Auckland', core_date::normalise_timezone('Pacific/Auckland'));
58 $this->assertSame('Pacific/Auckland', core_date::normalise_timezone('99'));
59 $this->assertSame('Pacific/Auckland', core_date::normalise_timezone(99));
60 $this->assertSame('GMT', core_date::normalise_timezone('GMT'));
61 $this->assertSame('UTC', core_date::normalise_timezone('UTC'));
62 $this->assertSame('Pacific/Auckland', core_date::normalise_timezone('xxxxxxxx'));
63 $this->assertSame('Europe/Berlin', core_date::normalise_timezone('Central European Time'));
64 $this->assertSame('Etc/GMT', core_date::normalise_timezone('0'));
65 $this->assertSame('Etc/GMT', core_date::normalise_timezone('0.0'));
66 $this->assertSame('Etc/GMT-2', core_date::normalise_timezone(2));
67 $this->assertSame('Etc/GMT-2', core_date::normalise_timezone('2.0'));
68 $this->assertSame('Etc/GMT+2', core_date::normalise_timezone(-2));
69 $this->assertSame('Etc/GMT+2', core_date::normalise_timezone('-2.0'));
70 $this->assertSame('Etc/GMT+4', core_date::normalise_timezone(-4));
71 $this->assertSame('Etc/GMT-2', core_date::normalise_timezone('UTC+2'));
72 $this->assertSame('Etc/GMT+2', core_date::normalise_timezone('UTC-2'));
73 $this->assertSame('Etc/GMT-2', core_date::normalise_timezone('GMT+2'));
74 $this->assertSame('Etc/GMT+2', core_date::normalise_timezone('GMT-2'));
75 $this->assertSame('Etc/GMT+12', core_date::normalise_timezone(-12));
76 $this->assertSame('Pacific/Auckland', core_date::normalise_timezone(-13));
77 $this->assertSame('Pacific/Auckland', core_date::normalise_timezone(-14));
78 $this->assertSame('Etc/GMT-12', core_date::normalise_timezone(12));
79 $this->assertSame('Etc/GMT-13', core_date::normalise_timezone(13));
80 $this->assertSame('Pacific/Auckland', core_date::normalise_timezone(14));
82 $this->assertSame('Asia/Kabul', core_date::normalise_timezone(4.5));
83 $this->assertSame('Asia/Kolkata', core_date::normalise_timezone(5.5));
84 $this->assertSame('Asia/Rangoon', core_date::normalise_timezone(6.5));
85 $this->assertSame('Australia/Darwin', core_date::normalise_timezone('9.5'));
87 $this->setTimezone('99', 'Pacific/Auckland');
88 $this->assertSame('Pacific/Auckland', core_date::normalise_timezone('Pacific/Auckland'));
89 $this->assertSame('Pacific/Auckland', core_date::normalise_timezone('99'));
90 $this->assertSame('Pacific/Auckland', core_date::normalise_timezone(99));
91 $this->assertSame('GMT', core_date::normalise_timezone('GMT'));
92 $this->assertSame('UTC', core_date::normalise_timezone('UTC'));
93 $this->assertSame('Pacific/Auckland', core_date::normalise_timezone('xxxxxxxx'));
94 $this->assertSame('Europe/Berlin', core_date::normalise_timezone('Central European Time'));
95 $this->assertSame('Etc/GMT', core_date::normalise_timezone('0'));
96 $this->assertSame('Etc/GMT', core_date::normalise_timezone('0.0'));
97 $this->assertSame('Etc/GMT-2', core_date::normalise_timezone(2));
98 $this->assertSame('Etc/GMT-2', core_date::normalise_timezone('2.0'));
99 $this->assertSame('Etc/GMT+2', core_date::normalise_timezone(-2));
100 $this->assertSame('Etc/GMT+2', core_date::normalise_timezone('-2.0'));
101 $this->assertSame('Etc/GMT-2', core_date::normalise_timezone('UTC+2'));
102 $this->assertSame('Etc/GMT+2', core_date::normalise_timezone('UTC-2'));
103 $this->assertSame('Etc/GMT-2', core_date::normalise_timezone('GMT+2'));
104 $this->assertSame('Etc/GMT+2', core_date::normalise_timezone('GMT-2'));
105 $this->assertSame('Etc/GMT+12', core_date::normalise_timezone(-12));
106 $this->assertSame('Pacific/Auckland', core_date::normalise_timezone(-13));
107 $this->assertSame('Pacific/Auckland', core_date::normalise_timezone(-14));
108 $this->assertSame('Etc/GMT-12', core_date::normalise_timezone(12));
109 $this->assertSame('Etc/GMT-13', core_date::normalise_timezone(13));
110 $this->assertSame('Pacific/Auckland', core_date::normalise_timezone(14));
112 $this->setTimezone('Pacific/Auckland', 'Pacific/Auckland');
113 $tz = new DateTimeZone('Pacific/Auckland');
114 $this->assertSame('Pacific/Auckland', core_date::normalise_timezone($tz));
117 public function test_windows_conversion() {
118 $file = __DIR__ . '/fixtures/timezonewindows.xml';
120 $contents = file_get_contents($file);
121 preg_match_all('/<mapZone other="([^"]+)" territory="001" type="([^"]+)"\/>/', $contents, $matches, PREG_SET_ORDER);
123 $this->assertCount(104, $matches); // NOTE: If the file contents change edit the core_date class and update this.
125 foreach ($matches as $match) {
126 $result = core_date::normalise_timezone($match[1]);
127 if ($result == $match[2]) {
128 $this->assertSame($match[2], $result);
130 $data = new DateTime('now', new DateTimeZone($match[2]));
131 $expectedoffset = $data->getOffset();
132 $data = new DateTime('now', new DateTimeZone($result));
133 $resultoffset = $data->getOffset();
134 $this->assertSame($expectedoffset, $resultoffset, "$match[1] is expected to be converted to $match[2] not $result");
140 * Sanity test for PHP stuff.
142 public function test_php_gmt_offsets() {
143 $this->resetAfterTest();
145 $this->setTimezone('Pacific/Auckland', 'Pacific/Auckland');
147 for ($i = -12; $i < 0; $i++) {
148 $date = new DateTime('now', new DateTimeZone("Etc/GMT{$i}"));
149 $this->assertSame(- $i * 60 * 60, $date->getOffset());
150 $date = new DateTime('now', new DateTimeZone(core_date::normalise_timezone("GMT{$i}")));
151 $this->assertSame($i * 60 * 60, $date->getOffset());
152 $date = new DateTime('now', new DateTimeZone(core_date::normalise_timezone("UTC{$i}")));
153 $this->assertSame($i * 60 * 60, $date->getOffset());
156 $date = new DateTime('now', new DateTimeZone('Etc/GMT'));
157 $this->assertSame(0, $date->getOffset());
159 for ($i = 1; $i <= 12; $i++) {
160 $date = new DateTime('now', new DateTimeZone("Etc/GMT+{$i}"));
161 $this->assertSame(- $i * 60 * 60, $date->getOffset());
162 $date = new DateTime('now', new DateTimeZone(core_date::normalise_timezone("GMT+{$i}")));
163 $this->assertSame($i * 60 * 60, $date->getOffset());
164 $date = new DateTime('now', new DateTimeZone(core_date::normalise_timezone("UTC+{$i}")));
165 $this->assertSame($i * 60 * 60, $date->getOffset());
169 public function test_get_localised_timezone() {
170 $this->resetAfterTest();
172 $this->setTimezone('Pacific/Auckland', 'Pacific/Auckland');
174 $result = core_date::get_localised_timezone('Pacific/Auckland');
175 $this->assertSame('Pacific/Auckland', $result);
177 $result = core_date::get_localised_timezone('99');
178 $this->assertSame('Server timezone (Pacific/Auckland)', $result);
180 $result = core_date::get_localised_timezone(99);
181 $this->assertSame('Server timezone (Pacific/Auckland)', $result);
183 $result = core_date::get_localised_timezone('Etc/GMT-1');
184 $this->assertSame('UTC+1', $result);
186 $result = core_date::get_localised_timezone('Etc/GMT+2');
187 $this->assertSame('UTC-2', $result);
189 $result = core_date::get_localised_timezone('GMT');
190 $this->assertSame('UTC', $result);
192 $result = core_date::get_localised_timezone('Etc/GMT');
193 $this->assertSame('UTC', $result);
196 public function test_get_list_of_timezones() {
197 $this->resetAfterTest();
199 $this->setTimezone('Pacific/Auckland', 'Pacific/Auckland');
201 $phpzones = DateTimeZone::listIdentifiers();
203 $zones = core_date::get_list_of_timezones();
204 $this->assertSame(count($phpzones), count($zones));
205 foreach ($zones as $zone => $zonename) {
206 $this->assertSame($zone, $zonename); // The same in English!
207 $this->assertContains($zone, $phpzones); // No extras expected.
210 $this->assertSame($zones, core_date::get_list_of_timezones(null, false));
212 $nnzones = core_date::get_list_of_timezones(null, true);
213 $last = $nnzones['99'];
214 $this->assertSame('Server timezone (Pacific/Auckland)', $last);
215 unset($nnzones['99']);
216 $this->assertSame($zones, $nnzones);
218 $nnzones = core_date::get_list_of_timezones('99', false);
219 $last = $nnzones['99'];
220 $this->assertSame('Server timezone (Pacific/Auckland)', $last);
221 unset($nnzones['99']);
222 $this->assertSame($zones, $nnzones);
224 $xxzones = core_date::get_list_of_timezones('xx', false);
225 $xx = $xxzones['xx'];
226 $this->assertSame('Invalid timezone "xx"', $xx);
227 unset($xxzones['xx']);
228 $this->assertSame($zones, $xxzones);
230 $xxzones = core_date::get_list_of_timezones('1', false);
232 $this->assertSame('Invalid timezone "UTC+1.0"', $xx);
233 unset($xxzones['1']);
234 $this->assertSame($zones, $xxzones);
236 $xxzones = core_date::get_list_of_timezones('-1.5', false);
237 $xx = $xxzones['-1.5'];
238 $this->assertSame('Invalid timezone "UTC-1.5"', $xx);
239 unset($xxzones['-1.5']);
240 $this->assertSame($zones, $xxzones);
244 public function test_get_server_timezone() {
246 $this->resetAfterTest();
248 $this->setTimezone('Pacific/Auckland', 'Pacific/Auckland');
249 $this->assertSame('Pacific/Auckland', core_date::get_server_timezone());
251 $this->setTimezone('Pacific/Auckland', 'Europe/Prague');
252 $this->assertSame('Pacific/Auckland', core_date::get_server_timezone());
254 $this->setTimezone('99', 'Pacific/Auckland');
255 $this->assertSame('Pacific/Auckland', core_date::get_server_timezone());
257 $this->setTimezone(99, 'Pacific/Auckland');
258 $this->assertSame('Pacific/Auckland', core_date::get_server_timezone());
260 $this->setTimezone('Pacific/Auckland', 'Pacific/Auckland');
261 unset($CFG->timezone);
262 $this->assertSame('Pacific/Auckland', core_date::get_server_timezone());
264 // Admin should fix the settings.
265 $this->setTimezone('xxx/zzzz', 'Europe/Prague');
266 $this->assertSame('Europe/Prague', core_date::get_server_timezone());
269 public function test_get_server_timezone_object() {
270 $this->resetAfterTest();
272 $zones = core_date::get_list_of_timezones();
273 foreach ($zones as $zone) {
274 $this->setTimezone($zone, 'Pacific/Auckland');
275 $tz = core_date::get_server_timezone_object();
276 $this->assertInstanceOf('DateTimeZone', $tz);
277 $this->assertSame($zone, $tz->getName());
281 public function test_set_default_server_timezone() {
283 $this->resetAfterTest();
285 $this->setTimezone('Europe/Prague', 'Pacific/Auckland');
286 unset($CFG->timezone);
287 date_default_timezone_set('UTC');
288 core_date::set_default_server_timezone();
289 $this->assertSame('Pacific/Auckland', date_default_timezone_get());
291 $this->setTimezone('', 'Pacific/Auckland');
292 date_default_timezone_set('UTC');
293 core_date::set_default_server_timezone();
294 $this->assertSame('Pacific/Auckland', date_default_timezone_get());
296 $this->setTimezone('99', 'Pacific/Auckland');
297 date_default_timezone_set('UTC');
298 core_date::set_default_server_timezone();
299 $this->assertSame('Pacific/Auckland', date_default_timezone_get());
301 $this->setTimezone(99, 'Pacific/Auckland');
302 date_default_timezone_set('UTC');
303 core_date::set_default_server_timezone();
304 $this->assertSame('Pacific/Auckland', date_default_timezone_get());
306 $this->setTimezone('Europe/Prague', 'Pacific/Auckland');
307 $CFG->timezone = 'UTC';
308 core_date::set_default_server_timezone();
309 $this->assertSame('UTC', date_default_timezone_get());
311 $this->setTimezone('Europe/Prague', 'Pacific/Auckland');
312 $CFG->timezone = 'Australia/Perth';
313 core_date::set_default_server_timezone();
314 $this->assertSame('Australia/Perth', date_default_timezone_get());
316 $this->setTimezone('0', 'Pacific/Auckland');
317 date_default_timezone_set('UTC');
318 core_date::set_default_server_timezone();
319 $this->assertSame('Etc/GMT', date_default_timezone_get());
321 $this->setTimezone('1', 'Pacific/Auckland');
322 date_default_timezone_set('UTC');
323 core_date::set_default_server_timezone();
324 $this->assertSame('Etc/GMT-1', date_default_timezone_get());
326 $this->setTimezone(1, 'Pacific/Auckland');
327 date_default_timezone_set('UTC');
328 core_date::set_default_server_timezone();
329 $this->assertSame('Etc/GMT-1', date_default_timezone_get());
331 $this->setTimezone('1.0', 'Pacific/Auckland');
332 date_default_timezone_set('UTC');
333 core_date::set_default_server_timezone();
334 $this->assertSame('Etc/GMT-1', date_default_timezone_get());
337 public function test_get_user_timezone() {
339 $this->resetAfterTest();
343 $this->setTimezone('Europe/Prague', 'Pacific/Auckland');
344 $USER->timezone = 'Pacific/Auckland';
345 $CFG->forcetimezone = '99';
346 $this->assertSame('Pacific/Auckland', core_date::get_user_timezone(null));
347 $this->assertSame('Pacific/Auckland', core_date::get_user_timezone());
349 $this->setTimezone('Europe/Prague', 'Pacific/Auckland');
350 $USER->timezone = 'Pacific/Auckland';
351 $CFG->forcetimezone = 'Europe/Berlin';
352 $this->assertSame('Europe/Berlin', core_date::get_user_timezone(null));
353 $this->assertSame('Europe/Berlin', core_date::get_user_timezone());
355 $this->setTimezone('Europe/Prague', 'Pacific/Auckland');
356 $USER->timezone = 'Pacific/Auckland';
357 $CFG->forcetimezone = 'xxx/yyy';
358 $this->assertSame('Europe/Prague', core_date::get_user_timezone(null));
359 $this->assertSame('Europe/Prague', core_date::get_user_timezone());
361 $this->setTimezone('Europe/Prague', 'Pacific/Auckland');
362 $USER->timezone = 'abc/def';
363 $CFG->forcetimezone = '99';
364 $this->assertSame('Europe/Prague', core_date::get_user_timezone(null));
365 $this->assertSame('Europe/Prague', core_date::get_user_timezone());
367 $this->setTimezone('xxx/yyy', 'Europe/London');
368 $USER->timezone = 'abc/def';
369 $CFG->forcetimezone = 'Europe/Berlin';
370 $this->assertSame('Europe/Berlin', core_date::get_user_timezone(null));
371 $this->assertSame('Europe/Berlin', core_date::get_user_timezone());
373 $this->setTimezone('xxx/yyy', 'Europe/London');
374 $USER->timezone = 'abc/def';
375 $CFG->forcetimezone = 99;
376 $this->assertSame('Europe/London', core_date::get_user_timezone(null));
377 $this->assertSame('Europe/London', core_date::get_user_timezone());
379 // User object parameter.
380 $admin = get_admin();
382 $this->setTimezone('Europe/London');
383 $USER->timezone = 'Pacific/Auckland';
384 $CFG->forcetimezone = '99';
385 $admin->timezone = 'Australia/Perth';
386 $this->assertSame('Australia/Perth', core_date::get_user_timezone($admin));
388 $this->setTimezone('Europe/Prague');
389 $USER->timezone = 'Pacific/Auckland';
390 $CFG->forcetimezone = '99';
391 $admin->timezone = '99';
392 $this->assertSame('Europe/Prague', core_date::get_user_timezone($admin));
394 $this->setTimezone('99', 'Europe/London');
395 $USER->timezone = 'Pacific/Auckland';
396 $CFG->forcetimezone = '99';
397 $admin->timezone = '99';
398 $this->assertSame('Europe/London', core_date::get_user_timezone($admin));
400 $this->setTimezone('Europe/Prague');
401 $USER->timezone = 'Pacific/Auckland';
402 $CFG->forcetimezone = '99';
403 $admin->timezone = 'xx/zz';
404 $this->assertSame('Europe/Prague', core_date::get_user_timezone($admin));
406 $this->setTimezone('Europe/Prague');
407 $USER->timezone = 'Pacific/Auckland';
408 $CFG->forcetimezone = '99';
409 unset($admin->timezone);
410 $this->assertSame('Europe/Prague', core_date::get_user_timezone($admin));
412 $this->setTimezone('Europe/Prague');
413 $USER->timezone = 'Pacific/Auckland';
414 $CFG->forcetimezone = 'Europe/Berlin';
415 $admin->timezone = 'Australia/Perth';
416 $this->assertSame('Europe/Berlin', core_date::get_user_timezone($admin));
418 // Other scalar parameter.
420 $this->setTimezone('Europe/Prague');
421 $CFG->forcetimezone = '99';
423 $USER->timezone = 'Pacific/Auckland';
424 $this->assertSame('Pacific/Auckland', core_date::get_user_timezone('99'));
425 $this->assertSame('Etc/GMT-1', core_date::get_user_timezone('1'));
426 $this->assertSame('Etc/GMT+1', core_date::get_user_timezone(-1));
427 $this->assertSame('Europe/London', core_date::get_user_timezone('Europe/London'));
428 $USER->timezone = '99';
429 $this->assertSame('Europe/Prague', core_date::get_user_timezone('99'));
430 $this->assertSame('Europe/London', core_date::get_user_timezone('Europe/London'));
431 $this->assertSame('Europe/Prague', core_date::get_user_timezone('xxx/zzz'));
432 $USER->timezone = 'xxz/zzz';
433 $this->assertSame('Europe/Prague', core_date::get_user_timezone('99'));
435 $this->setTimezone('99', 'Europe/Prague');
436 $CFG->forcetimezone = '99';
438 $USER->timezone = 'Pacific/Auckland';
439 $this->assertSame('Pacific/Auckland', core_date::get_user_timezone('99'));
440 $this->assertSame('Europe/London', core_date::get_user_timezone('Europe/London'));
441 $USER->timezone = '99';
442 $this->assertSame('Europe/Prague', core_date::get_user_timezone('99'));
443 $this->assertSame('Europe/London', core_date::get_user_timezone('Europe/London'));
444 $this->assertSame('Europe/Prague', core_date::get_user_timezone('xxx/zzz'));
445 $USER->timezone = 99;
446 $this->assertSame('Europe/London', core_date::get_user_timezone('Europe/London'));
447 $this->assertSame('Europe/Prague', core_date::get_user_timezone('xxx/zzz'));
448 $USER->timezone = 'xxz/zzz';
449 $this->assertSame('Europe/Prague', core_date::get_user_timezone('99'));
451 $this->setTimezone('xxx', 'Europe/Prague');
452 $CFG->forcetimezone = '99';
453 $USER->timezone = 'xxx';
454 $this->assertSame('Europe/Prague', core_date::get_user_timezone('99'));
455 $this->assertSame('Europe/Prague', core_date::get_user_timezone(99));
456 $this->assertSame('Etc/GMT-1', core_date::get_user_timezone(1));
458 $this->setTimezone('Europe/Prague');
459 $CFG->forcetimezone = 'Pacific/Auckland';
460 $USER->timezone = 'Europe/London';
461 $this->assertSame('Pacific/Auckland', core_date::get_user_timezone(99));
462 $this->assertSame('Europe/Berlin', core_date::get_user_timezone('Europe/Berlin'));
466 $this->setTimezone('UTC');
467 $USER->timezone = 'Europe/London';
468 $CFG->forcetimezone = 99;
469 $tz = new DateTimeZone('Pacific/Auckland');
470 $this->assertSame('Pacific/Auckland', core_date::get_user_timezone($tz));
473 public function test_get_user_timezone_object() {
475 $this->resetAfterTest();
477 $this->setTimezone('Pacific/Auckland');
478 $CFG->forcetimezone = '99';
480 $zones = core_date::get_list_of_timezones();
481 foreach ($zones as $zone) {
482 $USER->timezone = $zone;
483 $tz = core_date::get_user_timezone_object();
484 $this->assertInstanceOf('DateTimeZone', $tz);
485 $this->assertSame($zone, $tz->getName());