c84fcf0fda12b27f2aada9eac6ad09ab059240fe
[moodle.git] / lib / tests / date_test.php
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/>.
17 /**
18  * Tests core_date class.
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  */
26 defined('MOODLE_INTERNAL') || die();
28 /**
29  * Tests core_date class.
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_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());
51     }
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-2', core_date::normalise_timezone('UTC+2'));
71         $this->assertSame('Etc/GMT+2', core_date::normalise_timezone('UTC-2'));
72         $this->assertSame('Etc/GMT-2', core_date::normalise_timezone('GMT+2'));
73         $this->assertSame('Etc/GMT+2', core_date::normalise_timezone('GMT-2'));
74         $this->assertSame('Etc/GMT+12', core_date::normalise_timezone(-12));
75         $this->assertSame('Pacific/Auckland', core_date::normalise_timezone(-13));
76         $this->assertSame('Pacific/Auckland', core_date::normalise_timezone(-14));
77         $this->assertSame('Etc/GMT-12', core_date::normalise_timezone(12));
78         $this->assertSame('Etc/GMT-13', core_date::normalise_timezone(13));
79         $this->assertSame('Pacific/Auckland', core_date::normalise_timezone(14));
81         $this->assertSame('America/Caracas', core_date::normalise_timezone(-4.5));
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'));
86         $this->assertSame('Pacific/Norfolk', core_date::normalise_timezone('11.5'));
88         $this->setTimezone('99', 'Pacific/Auckland');
89         $this->assertSame('Pacific/Auckland', core_date::normalise_timezone('Pacific/Auckland'));
90         $this->assertSame('Pacific/Auckland', core_date::normalise_timezone('99'));
91         $this->assertSame('Pacific/Auckland', core_date::normalise_timezone(99));
92         $this->assertSame('GMT', core_date::normalise_timezone('GMT'));
93         $this->assertSame('UTC', core_date::normalise_timezone('UTC'));
94         $this->assertSame('Pacific/Auckland', core_date::normalise_timezone('xxxxxxxx'));
95         $this->assertSame('Europe/Berlin', core_date::normalise_timezone('Central European Time'));
96         $this->assertSame('Etc/GMT', core_date::normalise_timezone('0'));
97         $this->assertSame('Etc/GMT', core_date::normalise_timezone('0.0'));
98         $this->assertSame('Etc/GMT-2', core_date::normalise_timezone(2));
99         $this->assertSame('Etc/GMT-2', core_date::normalise_timezone('2.0'));
100         $this->assertSame('Etc/GMT+2', core_date::normalise_timezone(-2));
101         $this->assertSame('Etc/GMT+2', core_date::normalise_timezone('-2.0'));
102         $this->assertSame('Etc/GMT-2', core_date::normalise_timezone('UTC+2'));
103         $this->assertSame('Etc/GMT+2', core_date::normalise_timezone('UTC-2'));
104         $this->assertSame('Etc/GMT-2', core_date::normalise_timezone('GMT+2'));
105         $this->assertSame('Etc/GMT+2', core_date::normalise_timezone('GMT-2'));
106         $this->assertSame('Etc/GMT+12', core_date::normalise_timezone(-12));
107         $this->assertSame('Pacific/Auckland', core_date::normalise_timezone(-13));
108         $this->assertSame('Pacific/Auckland', core_date::normalise_timezone(-14));
109         $this->assertSame('Etc/GMT-12', core_date::normalise_timezone(12));
110         $this->assertSame('Etc/GMT-13', core_date::normalise_timezone(13));
111         $this->assertSame('Pacific/Auckland', core_date::normalise_timezone(14));
113         $this->setTimezone('Pacific/Auckland', 'Pacific/Auckland');
114         $tz = new DateTimeZone('Pacific/Auckland');
115         $this->assertSame('Pacific/Auckland', core_date::normalise_timezone($tz));
116     }
118     public function test_windows_conversion() {
119         $file = __DIR__ . '/fixtures/timezonewindows.xml';
121         $contents = file_get_contents($file);
122         preg_match_all('/<mapZone other="([^"]+)" territory="001" type="([^"]+)"\/>/', $contents, $matches, PREG_SET_ORDER);
124         $this->assertCount(104, $matches); // NOTE: If the file contents change edit the core_date class and update this.
126         foreach ($matches as $match) {
127             $result = core_date::normalise_timezone($match[1]);
128             if ($result == $match[2]) {
129                 $this->assertSame($match[2], $result);
130             } else {
131                 $data = new DateTime('now', new DateTimeZone($match[2]));
132                 $expectedoffset = $data->getOffset();
133                 $data = new DateTime('now', new DateTimeZone($result));
134                 $resultoffset = $data->getOffset();
135                 $this->assertSame($expectedoffset, $resultoffset, "$match[1] is expected to be converted to $match[2] not $result");
136             }
137         }
138     }
140     /**
141      * Sanity test for PHP stuff.
142      */
143     public function test_php_gmt_offsets() {
144         $this->resetAfterTest();
146         $this->setTimezone('Pacific/Auckland', 'Pacific/Auckland');
148         for ($i = -12; $i < 0; $i++) {
149             $date = new DateTime('now', new DateTimeZone("Etc/GMT{$i}"));
150             $this->assertSame(- $i * 60 * 60, $date->getOffset());
151             $date = new DateTime('now', new DateTimeZone(core_date::normalise_timezone("GMT{$i}")));
152             $this->assertSame($i * 60 * 60, $date->getOffset());
153             $date = new DateTime('now', new DateTimeZone(core_date::normalise_timezone("UTC{$i}")));
154             $this->assertSame($i * 60 * 60, $date->getOffset());
155         }
157         $date = new DateTime('now', new DateTimeZone('Etc/GMT'));
158         $this->assertSame(0, $date->getOffset());
160         for ($i = 1; $i <= 12; $i++) {
161             $date = new DateTime('now', new DateTimeZone("Etc/GMT+{$i}"));
162             $this->assertSame(- $i * 60 * 60, $date->getOffset());
163             $date = new DateTime('now', new DateTimeZone(core_date::normalise_timezone("GMT+{$i}")));
164             $this->assertSame($i * 60 * 60, $date->getOffset());
165             $date = new DateTime('now', new DateTimeZone(core_date::normalise_timezone("UTC+{$i}")));
166             $this->assertSame($i * 60 * 60, $date->getOffset());
167         }
168     }
170     public function test_get_localised_timezone() {
171         $this->resetAfterTest();
173         $this->setTimezone('Pacific/Auckland', 'Pacific/Auckland');
175         $result = core_date::get_localised_timezone('Pacific/Auckland');
176         $this->assertSame('Pacific/Auckland', $result);
178         $result = core_date::get_localised_timezone('99');
179         $this->assertSame('Server timezone (Pacific/Auckland)', $result);
181         $result = core_date::get_localised_timezone(99);
182         $this->assertSame('Server timezone (Pacific/Auckland)', $result);
184         $result = core_date::get_localised_timezone('Etc/GMT-1');
185         $this->assertSame('UTC+1', $result);
187         $result = core_date::get_localised_timezone('Etc/GMT+2');
188         $this->assertSame('UTC-2', $result);
190         $result = core_date::get_localised_timezone('GMT');
191         $this->assertSame('UTC', $result);
193         $result = core_date::get_localised_timezone('Etc/GMT');
194         $this->assertSame('UTC', $result);
195     }
197     public function test_get_list_of_timezones() {
198         $this->resetAfterTest();
200         $this->setTimezone('Pacific/Auckland', 'Pacific/Auckland');
202         $phpzones = DateTimeZone::listIdentifiers();
204         $zones = core_date::get_list_of_timezones();
205         $this->assertSame(count($phpzones), count($zones));
206         foreach ($zones as $zone => $zonename) {
207             $this->assertSame($zone, $zonename); // The same in English!
208             $this->assertContains($zone, $phpzones); // No extras expected.
209         }
211         $this->assertSame($zones, core_date::get_list_of_timezones(null, false));
213         $nnzones = core_date::get_list_of_timezones(null, true);
214         $last = $nnzones['99'];
215         $this->assertSame('Server timezone (Pacific/Auckland)', $last);
216         unset($nnzones['99']);
217         $this->assertSame($zones, $nnzones);
219         $nnzones = core_date::get_list_of_timezones('99', false);
220         $last = $nnzones['99'];
221         $this->assertSame('Server timezone (Pacific/Auckland)', $last);
222         unset($nnzones['99']);
223         $this->assertSame($zones, $nnzones);
225         $xxzones = core_date::get_list_of_timezones('xx', false);
226         $xx = $xxzones['xx'];
227         $this->assertSame('Invalid timezone "xx"', $xx);
228         unset($xxzones['xx']);
229         $this->assertSame($zones, $xxzones);
231         $xxzones = core_date::get_list_of_timezones('1', false);
232         $xx = $xxzones['1'];
233         $this->assertSame('Invalid timezone "UTC+1.0"', $xx);
234         unset($xxzones['1']);
235         $this->assertSame($zones, $xxzones);
237         $xxzones = core_date::get_list_of_timezones('-1.5', false);
238         $xx = $xxzones['-1.5'];
239         $this->assertSame('Invalid timezone "UTC-1.5"', $xx);
240         unset($xxzones['-1.5']);
241         $this->assertSame($zones, $xxzones);
243     }
245     public function test_get_server_timezone() {
246         global $CFG;
247         $this->resetAfterTest();
249         $this->setTimezone('Pacific/Auckland', 'Pacific/Auckland');
250         $this->assertSame('Pacific/Auckland', core_date::get_server_timezone());
252         $this->setTimezone('Pacific/Auckland', 'Europe/Prague');
253         $this->assertSame('Pacific/Auckland', core_date::get_server_timezone());
255         $this->setTimezone('99', 'Pacific/Auckland');
256         $this->assertSame('Pacific/Auckland', core_date::get_server_timezone());
258         $this->setTimezone(99, 'Pacific/Auckland');
259         $this->assertSame('Pacific/Auckland', core_date::get_server_timezone());
261         $this->setTimezone('Pacific/Auckland', 'Pacific/Auckland');
262         unset($CFG->timezone);
263         $this->assertSame('Pacific/Auckland', core_date::get_server_timezone());
265         // Admin should fix the settings.
266         $this->setTimezone('xxx/zzzz', 'Europe/Prague');
267         $this->assertSame('Europe/Prague', core_date::get_server_timezone());
268     }
270     public function test_get_server_timezone_object() {
271         $this->resetAfterTest();
273         $zones = core_date::get_list_of_timezones();
274         foreach ($zones as $zone) {
275             $this->setTimezone($zone, 'Pacific/Auckland');
276             $tz = core_date::get_server_timezone_object();
277             $this->assertInstanceOf('DateTimeZone', $tz);
278             $this->assertSame($zone, $tz->getName());
279         }
280     }
282     public function test_set_default_server_timezone() {
283         global $CFG;
284         $this->resetAfterTest();
286         $this->setTimezone('Europe/Prague', 'Pacific/Auckland');
287         unset($CFG->timezone);
288         date_default_timezone_set('UTC');
289         core_date::set_default_server_timezone();
290         $this->assertSame('Pacific/Auckland', date_default_timezone_get());
292         $this->setTimezone('', 'Pacific/Auckland');
293         date_default_timezone_set('UTC');
294         core_date::set_default_server_timezone();
295         $this->assertSame('Pacific/Auckland', date_default_timezone_get());
297         $this->setTimezone('99', 'Pacific/Auckland');
298         date_default_timezone_set('UTC');
299         core_date::set_default_server_timezone();
300         $this->assertSame('Pacific/Auckland', date_default_timezone_get());
302         $this->setTimezone(99, 'Pacific/Auckland');
303         date_default_timezone_set('UTC');
304         core_date::set_default_server_timezone();
305         $this->assertSame('Pacific/Auckland', date_default_timezone_get());
307         $this->setTimezone('Europe/Prague', 'Pacific/Auckland');
308         $CFG->timezone = 'UTC';
309         core_date::set_default_server_timezone();
310         $this->assertSame('UTC', date_default_timezone_get());
312         $this->setTimezone('Europe/Prague', 'Pacific/Auckland');
313         $CFG->timezone = 'Australia/Perth';
314         core_date::set_default_server_timezone();
315         $this->assertSame('Australia/Perth', date_default_timezone_get());
317         $this->setTimezone('0', 'Pacific/Auckland');
318         date_default_timezone_set('UTC');
319         core_date::set_default_server_timezone();
320         $this->assertSame('Etc/GMT', date_default_timezone_get());
322         $this->setTimezone('1', 'Pacific/Auckland');
323         date_default_timezone_set('UTC');
324         core_date::set_default_server_timezone();
325         $this->assertSame('Etc/GMT-1', date_default_timezone_get());
327         $this->setTimezone(1, 'Pacific/Auckland');
328         date_default_timezone_set('UTC');
329         core_date::set_default_server_timezone();
330         $this->assertSame('Etc/GMT-1', date_default_timezone_get());
332         $this->setTimezone('1.0', 'Pacific/Auckland');
333         date_default_timezone_set('UTC');
334         core_date::set_default_server_timezone();
335         $this->assertSame('Etc/GMT-1', date_default_timezone_get());
336     }
338     public function test_get_user_timezone() {
339         global $CFG, $USER;
340         $this->resetAfterTest();
342         // Null parameter.
344         $this->setTimezone('Europe/Prague', 'Pacific/Auckland');
345         $USER->timezone = 'Pacific/Auckland';
346         $CFG->forcetimezone = '99';
347         $this->assertSame('Pacific/Auckland', core_date::get_user_timezone(null));
348         $this->assertSame('Pacific/Auckland', core_date::get_user_timezone());
350         $this->setTimezone('Europe/Prague', 'Pacific/Auckland');
351         $USER->timezone = 'Pacific/Auckland';
352         $CFG->forcetimezone = 'Europe/Berlin';
353         $this->assertSame('Europe/Berlin', core_date::get_user_timezone(null));
354         $this->assertSame('Europe/Berlin', core_date::get_user_timezone());
356         $this->setTimezone('Europe/Prague', 'Pacific/Auckland');
357         $USER->timezone = 'Pacific/Auckland';
358         $CFG->forcetimezone = 'xxx/yyy';
359         $this->assertSame('Europe/Prague', core_date::get_user_timezone(null));
360         $this->assertSame('Europe/Prague', core_date::get_user_timezone());
362         $this->setTimezone('Europe/Prague', 'Pacific/Auckland');
363         $USER->timezone = 'abc/def';
364         $CFG->forcetimezone = '99';
365         $this->assertSame('Europe/Prague', core_date::get_user_timezone(null));
366         $this->assertSame('Europe/Prague', core_date::get_user_timezone());
368         $this->setTimezone('xxx/yyy', 'Europe/London');
369         $USER->timezone = 'abc/def';
370         $CFG->forcetimezone = 'Europe/Berlin';
371         $this->assertSame('Europe/Berlin', core_date::get_user_timezone(null));
372         $this->assertSame('Europe/Berlin', core_date::get_user_timezone());
374         $this->setTimezone('xxx/yyy', 'Europe/London');
375         $USER->timezone = 'abc/def';
376         $CFG->forcetimezone = 99;
377         $this->assertSame('Europe/London', core_date::get_user_timezone(null));
378         $this->assertSame('Europe/London', core_date::get_user_timezone());
380         // User object parameter.
381         $admin = get_admin();
383         $this->setTimezone('Europe/London');
384         $USER->timezone = 'Pacific/Auckland';
385         $CFG->forcetimezone = '99';
386         $admin->timezone = 'Australia/Perth';
387         $this->assertSame('Australia/Perth', core_date::get_user_timezone($admin));
389         $this->setTimezone('Europe/Prague');
390         $USER->timezone = 'Pacific/Auckland';
391         $CFG->forcetimezone = '99';
392         $admin->timezone = '99';
393         $this->assertSame('Europe/Prague', core_date::get_user_timezone($admin));
395         $this->setTimezone('99', 'Europe/London');
396         $USER->timezone = 'Pacific/Auckland';
397         $CFG->forcetimezone = '99';
398         $admin->timezone = '99';
399         $this->assertSame('Europe/London', core_date::get_user_timezone($admin));
401         $this->setTimezone('Europe/Prague');
402         $USER->timezone = 'Pacific/Auckland';
403         $CFG->forcetimezone = '99';
404         $admin->timezone = 'xx/zz';
405         $this->assertSame('Europe/Prague', core_date::get_user_timezone($admin));
407         $this->setTimezone('Europe/Prague');
408         $USER->timezone = 'Pacific/Auckland';
409         $CFG->forcetimezone = '99';
410         unset($admin->timezone);
411         $this->assertSame('Europe/Prague', core_date::get_user_timezone($admin));
413         $this->setTimezone('Europe/Prague');
414         $USER->timezone = 'Pacific/Auckland';
415         $CFG->forcetimezone = 'Europe/Berlin';
416         $admin->timezone = 'Australia/Perth';
417         $this->assertSame('Europe/Berlin', core_date::get_user_timezone($admin));
419         // Other scalar parameter.
421         $this->setTimezone('Europe/Prague');
422         $CFG->forcetimezone = '99';
424         $USER->timezone = 'Pacific/Auckland';
425         $this->assertSame('Pacific/Auckland', core_date::get_user_timezone('99'));
426         $this->assertSame('Etc/GMT-1', core_date::get_user_timezone('1'));
427         $this->assertSame('Etc/GMT+1', core_date::get_user_timezone(-1));
428         $this->assertSame('Europe/London', core_date::get_user_timezone('Europe/London'));
429         $USER->timezone = '99';
430         $this->assertSame('Europe/Prague', core_date::get_user_timezone('99'));
431         $this->assertSame('Europe/London', core_date::get_user_timezone('Europe/London'));
432         $this->assertSame('Europe/Prague', core_date::get_user_timezone('xxx/zzz'));
433         $USER->timezone = 'xxz/zzz';
434         $this->assertSame('Europe/Prague', core_date::get_user_timezone('99'));
436         $this->setTimezone('99', 'Europe/Prague');
437         $CFG->forcetimezone = '99';
439         $USER->timezone = 'Pacific/Auckland';
440         $this->assertSame('Pacific/Auckland', core_date::get_user_timezone('99'));
441         $this->assertSame('Europe/London', core_date::get_user_timezone('Europe/London'));
442         $USER->timezone = '99';
443         $this->assertSame('Europe/Prague', core_date::get_user_timezone('99'));
444         $this->assertSame('Europe/London', core_date::get_user_timezone('Europe/London'));
445         $this->assertSame('Europe/Prague', core_date::get_user_timezone('xxx/zzz'));
446         $USER->timezone = 99;
447         $this->assertSame('Europe/London', core_date::get_user_timezone('Europe/London'));
448         $this->assertSame('Europe/Prague', core_date::get_user_timezone('xxx/zzz'));
449         $USER->timezone = 'xxz/zzz';
450         $this->assertSame('Europe/Prague', core_date::get_user_timezone('99'));
452         $this->setTimezone('xxx', 'Europe/Prague');
453         $CFG->forcetimezone = '99';
454         $USER->timezone = 'xxx';
455         $this->assertSame('Europe/Prague', core_date::get_user_timezone('99'));
456         $this->assertSame('Europe/Prague', core_date::get_user_timezone(99));
457         $this->assertSame('Etc/GMT-1', core_date::get_user_timezone(1));
459         $this->setTimezone('Europe/Prague');
460         $CFG->forcetimezone = 'Pacific/Auckland';
461         $USER->timezone = 'Europe/London';
462         $this->assertSame('Pacific/Auckland', core_date::get_user_timezone(99));
463         $this->assertSame('Europe/Berlin', core_date::get_user_timezone('Europe/Berlin'));
465         // TZ object param.
467         $this->setTimezone('UTC');
468         $USER->timezone = 'Europe/London';
469         $CFG->forcetimezone = 99;
470         $tz = new DateTimeZone('Pacific/Auckland');
471         $this->assertSame('Pacific/Auckland', core_date::get_user_timezone($tz));
472     }
474     public function test_get_user_timezone_object() {
475         global $CFG, $USER;
476         $this->resetAfterTest();
478         $this->setTimezone('Pacific/Auckland');
479         $CFG->forcetimezone = '99';
481         $zones = core_date::get_list_of_timezones();
482         foreach ($zones as $zone) {
483             $USER->timezone = $zone;
484             $tz = core_date::get_user_timezone_object();
485             $this->assertInstanceOf('DateTimeZone', $tz);
486             $this->assertSame($zone, $tz->getName());
487         }
488     }