From e49cb057a15dd182402afafd27c06d1b19c4de55 Mon Sep 17 00:00:00 2001 From: Petr Skoda Date: Sun, 12 Apr 2015 12:11:10 +1200 Subject: [PATCH 1/4] MDL-49828 timezones: fix typos introduced by MDL-49684 --- backup/util/helper/backup_cron_helper.class.php | 4 ++-- lib/deprecatedlib.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backup/util/helper/backup_cron_helper.class.php b/backup/util/helper/backup_cron_helper.class.php index 18524bf7ce5..1188bf7fc54 100644 --- a/backup/util/helper/backup_cron_helper.class.php +++ b/backup/util/helper/backup_cron_helper.class.php @@ -315,11 +315,11 @@ abstract class backup_cron_automated_helper { /** * Works out the next time the automated backup should be run. * - * @param mixed $ignroedtimezone all settings are in server timezone! + * @param mixed $ignoredtimezone all settings are in server timezone! * @param int $now timestamp, should not be in the past, most likely time() * @return int timestamp of the next execution at server time */ - public static function calculate_next_automated_backup($ignroedtimezone, $now) { + public static function calculate_next_automated_backup($ignoredtimezone, $now) { $config = get_config('backup'); diff --git a/lib/deprecatedlib.php b/lib/deprecatedlib.php index 840734e8256..b45202fdf60 100644 --- a/lib/deprecatedlib.php +++ b/lib/deprecatedlib.php @@ -75,7 +75,7 @@ function get_timezone_offset($tz) { * @return array */ function get_list_of_timezones() { - debugging('update_timezone_records() is deprecated, use core_date::get_list_of_timezones() instead', DEBUG_DEVELOPER); + debugging('get_list_of_timezones() is deprecated, use core_date::get_list_of_timezones() instead', DEBUG_DEVELOPER); return core_date::get_list_of_timezones(); } From 75a1e85e3a31d8e4d74c1908615f1cdde99463ff Mon Sep 17 00:00:00 2001 From: Petr Skoda Date: Sun, 12 Apr 2015 12:37:32 +1200 Subject: [PATCH 2/4] MDL-49828 timezones: fix messed up phpunit detection --- lib/classes/date.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/classes/date.php b/lib/classes/date.php index 3ced6b6adef..c2d7b664a3d 100644 --- a/lib/classes/date.php +++ b/lib/classes/date.php @@ -296,7 +296,8 @@ class core_date { * To be called from lib/setup.php only! */ public static function store_default_php_timezone() { - if (defined('PHPUNIT_TEST') or defined('BEHAT_SITE_RUNNING') or defined('BEHAT_TEST') or defined('BEHAT_UTIL')) { + if ((defined('PHPUNIT_TEST') and PHPUNIT_TEST) + or defined('BEHAT_SITE_RUNNING') or defined('BEHAT_TEST') or defined('BEHAT_UTIL')) { // We want all test sites to be consistent by default. self::$defaultphptimezone = 'Australia/Perth'; return; From 91bafd76f56ae168eb5c49bb25e3a80b5e3914c0 Mon Sep 17 00:00:00 2001 From: Petr Skoda Date: Sun, 12 Apr 2015 12:38:06 +1200 Subject: [PATCH 3/4] MDL-49828 timezones: improve settings performance --- admin/settings/location.php | 22 +--------- lib/adminlib.php | 80 +++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 20 deletions(-) diff --git a/admin/settings/location.php b/admin/settings/location.php index 3666409c8dc..1868f3305d0 100644 --- a/admin/settings/location.php +++ b/admin/settings/location.php @@ -4,26 +4,8 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page // "locations" settingpage $temp = new admin_settingpage('locationsettings', new lang_string('locationsettings', 'admin')); - - $current = isset($CFG->timezone) ? $CFG->timezone : null; - $options = core_date::get_list_of_timezones($current, false); - $default = core_date::get_default_php_timezone(); - if ($current == 99) { - // Do not show 99 unless it is current value, we want to get rid of it over time. - $options['99'] = new lang_string('timezonephpdefault', 'core_admin', $default); - } - if ($default === 'UTC') { - // Nobody really wants UTC, so instead default selection to the country that is confused by the UTC the most. - $default = 'Europe/London'; - } - $temp->add(new admin_setting_configselect('timezone', new lang_string('timezone', 'admin'), - new lang_string('configtimezone', 'admin'), $default, $options)); - - $options = core_date::get_list_of_timezones(isset($CFG->forcetimezone) ? $CFG->forcetimezone : null, true); - $options[99] = new lang_string('timezonenotforced', 'admin'); - $temp->add(new admin_setting_configselect('forcetimezone', new lang_string('forcetimezone', 'admin'), - new lang_string('helpforcetimezone', 'admin'), 99, $options)); - + $temp->add(new admin_setting_servertimezone()); + $temp->add(new admin_setting_forcetimezone()); $temp->add(new admin_settings_country_select('country', new lang_string('country', 'admin'), new lang_string('configcountry', 'admin'), 0)); $temp->add(new admin_setting_configtext('defaultcity', new lang_string('defaultcity', 'admin'), new lang_string('defaultcity_help', 'admin'), '')); diff --git a/lib/adminlib.php b/lib/adminlib.php index 37da3db1b7e..897cc2f0a12 100644 --- a/lib/adminlib.php +++ b/lib/adminlib.php @@ -8997,3 +8997,83 @@ class admin_setting_php_extension_enabled extends admin_setting { return $o; } } + +/** + * Server timezone setting. + * + * @copyright 2015 Totara Learning Solutions Ltd {@link http://www.totaralms.com/} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @author Petr Skoda + */ +class admin_setting_servertimezone extends admin_setting_configselect { + /** + * Constructor. + */ + public function __construct() { + $default = core_date::get_default_php_timezone(); + if ($default === 'UTC') { + // Nobody really wants UTC, so instead default selection to the country that is confused by the UTC the most. + $default = 'Europe/London'; + } + + parent::__construct('timezone', + new lang_string('timezone', 'core_admin'), + new lang_string('configtimezone', 'core_admin'), $default, null); + } + + /** + * Lazy load timezone options. + * @return bool true if loaded, false if error + */ + public function load_choices() { + global $CFG; + if (is_array($this->choices)) { + return true; + } + + $current = isset($CFG->timezone) ? $CFG->timezone : null; + $this->choices = core_date::get_list_of_timezones($current, false); + if ($current == 99) { + // Do not show 99 unless it is current value, we want to get rid of it over time. + $this->choices['99'] = new lang_string('timezonephpdefault', 'core_admin', + core_date::get_default_php_timezone()); + } + + return true; + } +} + +/** + * Forced user timezone setting. + * + * @copyright 2015 Totara Learning Solutions Ltd {@link http://www.totaralms.com/} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @author Petr Skoda + */ +class admin_setting_forcetimezone extends admin_setting_configselect { + /** + * Constructor. + */ + public function __construct() { + parent::__construct('forcetimezone', + new lang_string('forcetimezone', 'core_admin'), + new lang_string('helpforcetimezone', 'core_admin'), '99', null); + } + + /** + * Lazy load timezone options. + * @return bool true if loaded, false if error + */ + public function load_choices() { + global $CFG; + if (is_array($this->choices)) { + return true; + } + + $current = isset($CFG->forcetimezone) ? $CFG->forcetimezone : null; + $this->choices = core_date::get_list_of_timezones($current, true); + $this->choices['99'] = new lang_string('timezonenotforced', 'core_admin'); + + return true; + } +} From 980a3a12ce6196f7d79a4c5ba76d5fa7bf2001ba Mon Sep 17 00:00:00 2001 From: Petr Skoda Date: Sun, 12 Apr 2015 13:47:06 +1200 Subject: [PATCH 4/4] MDL-49828 timezones: add tests for DST switching --- lib/tests/moodlelib_test.php | 73 ++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/lib/tests/moodlelib_test.php b/lib/tests/moodlelib_test.php index 47e00999c9d..cd40c1b3618 100644 --- a/lib/tests/moodlelib_test.php +++ b/lib/tests/moodlelib_test.php @@ -1357,6 +1357,79 @@ class core_moodlelib_testcase extends advanced_testcase { } } + /** + * Make sure the DST changes happen at the right time in Moodle. + */ + public function test_dst_changes() { + // DST switching in Prague. + // From 2AM to 3AM in 1989. + $date = new DateTime('1989-03-26T01:59:00+01:00'); + $this->assertSAMe('Sunday, 26 March 1989, 1:59', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'Europe/Prague')); + $date = new DateTime('1989-03-26T02:01:00+01:00'); + $this->assertSame('Sunday, 26 March 1989, 3:01', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'Europe/Prague')); + // From 3AM to 2AM in 1989 - not the same as the west Europe. + $date = new DateTime('1989-09-24T01:59:00+01:00'); + $this->assertSame('Sunday, 24 September 1989, 2:59', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'Europe/Prague')); + $date = new DateTime('1989-09-24T02:01:00+01:00'); + $this->assertSame('Sunday, 24 September 1989, 2:01', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'Europe/Prague')); + // From 2AM to 3AM in 2014. + $date = new DateTime('2014-03-30T01:59:00+01:00'); + $this->assertSame('Sunday, 30 March 2014, 1:59', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'Europe/Prague')); + $date = new DateTime('2014-03-30T02:01:00+01:00'); + $this->assertSame('Sunday, 30 March 2014, 3:01', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'Europe/Prague')); + // From 3AM to 2AM in 2014. + $date = new DateTime('2014-10-26T01:59:00+01:00'); + $this->assertSame('Sunday, 26 October 2014, 2:59', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'Europe/Prague')); + $date = new DateTime('2014-10-26T02:01:00+01:00'); + $this->assertSame('Sunday, 26 October 2014, 2:01', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'Europe/Prague')); + // From 2AM to 3AM in 2020. + $date = new DateTime('2020-03-29T01:59:00+01:00'); + $this->assertSame('Sunday, 29 March 2020, 1:59', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'Europe/Prague')); + $date = new DateTime('2020-03-29T02:01:00+01:00'); + $this->assertSame('Sunday, 29 March 2020, 3:01', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'Europe/Prague')); + // From 3AM to 2AM in 2020. + $date = new DateTime('2020-10-25T01:59:00+01:00'); + $this->assertSame('Sunday, 25 October 2020, 2:59', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'Europe/Prague')); + $date = new DateTime('2020-10-25T02:01:00+01:00'); + $this->assertSame('Sunday, 25 October 2020, 2:01', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'Europe/Prague')); + + // DST switching in NZ. + // From 3AM to 2AM in 2015. + $date = new DateTime('2015-04-05T02:59:00+13:00'); + $this->assertSame('Sunday, 5 April 2015, 2:59', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'Pacific/Auckland')); + $date = new DateTime('2015-04-05T03:01:00+13:00'); + $this->assertSame('Sunday, 5 April 2015, 2:01', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'Pacific/Auckland')); + // From 2AM to 3AM in 2009. + $date = new DateTime('2015-09-27T01:59:00+12:00'); + $this->assertSame('Sunday, 27 September 2015, 1:59', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'Pacific/Auckland')); + $date = new DateTime('2015-09-27T02:01:00+12:00'); + $this->assertSame('Sunday, 27 September 2015, 3:01', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'Pacific/Auckland')); + + // DST switching in Perth. + // From 3AM to 2AM in 2009. + $date = new DateTime('2008-03-30T01:59:00+08:00'); + $this->assertSame('Sunday, 30 March 2008, 2:59', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'Australia/Perth')); + $date = new DateTime('2008-03-30T02:01:00+08:00'); + $this->assertSame('Sunday, 30 March 2008, 2:01', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'Australia/Perth')); + // From 2AM to 3AM in 2009. + $date = new DateTime('2008-10-26T01:59:00+08:00'); + $this->assertSame('Sunday, 26 October 2008, 1:59', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'Australia/Perth')); + $date = new DateTime('2008-10-26T02:01:00+08:00'); + $this->assertSame('Sunday, 26 October 2008, 3:01', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'Australia/Perth')); + + // DST switching in US. + // From 2AM to 3AM in 2014. + $date = new DateTime('2014-03-09T01:59:00-05:00'); + $this->assertSame('Sunday, 9 March 2014, 1:59', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'America/New_York')); + $date = new DateTime('2014-03-09T02:01:00-05:00'); + $this->assertSame('Sunday, 9 March 2014, 3:01', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'America/New_York')); + // From 3AM to 2AM in 2014. + $date = new DateTime('2014-11-02T01:59:00-04:00'); + $this->assertSame('Sunday, 2 November 2014, 1:59', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'America/New_York')); + $date = new DateTime('2014-11-02T02:01:00-04:00'); + $this->assertSame('Sunday, 2 November 2014, 1:01', userdate($date->getTimestamp(), '%A, %d %B %Y,%k:%M', 'America/New_York')); + } + public function test_make_timestamp() { global $USER, $CFG, $DB; $this->resetAfterTest();