From 3fabb692265b73e2edb35ab0e914a47f31341503 Mon Sep 17 00:00:00 2001 From: Jon Stovell Date: Fri, 24 Mar 2017 19:56:11 -0600 Subject: [PATCH 1/9] Better handling of time zones abbreviations that PHP doesn't know Signed-off-by: Jon Stovell --- Sources/Subs-Calendar.php | 71 ++++++++++++++++++++++++++++++++------- Sources/Subs.php | 70 ++++++++++++++++++++++++++++++++------ 2 files changed, 118 insertions(+), 23 deletions(-) diff --git a/Sources/Subs-Calendar.php b/Sources/Subs-Calendar.php index 99134fce58..b8933bc708 100644 --- a/Sources/Subs-Calendar.php +++ b/Sources/Subs-Calendar.php @@ -1609,18 +1609,65 @@ function buildEventDatetimes($row) // There are a handful of time zones that PHP doesn't know the abbreviation for. Fix 'em if we can. if (strspn($tz_abbrev, '+-') > 0) { - $tz_location = timezone_location_get(timezone_open($row['timezone'])); - - // Kazakstan - if ($tz_location['country_code'] == 'KZ') - $tz_abbrev = str_replace(array('+05', '+06'), array('AQTT', 'ALMT'), $tz_abbrev); + $missing_tz_abbrs = array( + 'Antarctica/Casey' => 'CAST', + 'Antarctica/Davis' => 'DAVT', + 'Antarctica/DumontDUrville' => 'DDUT', + 'Antarctica/Mawson' => 'MAWT', + 'Antarctica/Rothera' => 'ART', + 'Antarctica/Syowa' => 'SYOT', + 'Antarctica/Troll' => 'CET', + 'Antarctica/Vostok' => 'VOST', + 'Asia/Almaty' => 'ALMT', + 'Asia/Anadyr' => 'ANAT', + 'Asia/Aqtau' => 'ORAT', + 'Asia/Aqtobe' => 'AQTT', + 'Asia/Ashgabat' => 'TMT', + 'Asia/Baku' => 'AZT', + 'Asia/Bishkek' => 'KGT', + 'Asia/Chita' => 'YAKT', + 'Asia/Colombo' => 'IST', + 'Asia/Dushanbe' => 'TJT', + 'Asia/Irkutsk' => 'IRKT', + 'Asia/Kamchatka' => 'PETT', + 'Asia/Khandyga' => 'YAKT', + 'Asia/Krasnoyarsk' => 'KRAT', + 'Asia/Magadan' => 'MAGT', + 'Asia/Novokuznetsk' => 'KRAT', + 'Asia/Novosibirsk' => 'NOVT', + 'Asia/Omsk' => 'OMST', + 'Asia/Oral' => 'ORAT', + 'Asia/Qyzylorda' => 'QYZT', + 'Asia/Sakhalin' => 'SAKT', + 'Asia/Samarkand' => 'UZT', + 'Asia/Srednekolymsk' => 'SRET', + 'Asia/Tashkent' => 'UZT', + 'Asia/Tbilisi' => 'GET', + 'Asia/Ust-Nera' => 'VLAT', + 'Asia/Vladivostok' => 'VLAT', + 'Asia/Yakutsk' => 'YAKT', + 'Asia/Yekaterinburg' => 'YEKT', + 'Asia/Yerevan' => 'AMT', + 'Europe/Istanbul' => 'TRT', + 'Europe/Kirov' => 'MSK', + 'Europe/Minsk' => 'MSK', + 'Europe/Samara' => 'SAMT', + 'Europe/Volgograd' => 'MSK', + 'Indian/Kerguelen' => 'TFT', + ); - // Russia likes to experiment with time zones - if ($tz_location['country_code'] == 'RU') + if (!empty($missing_tz_abbrs[$tz])) + $tz_abbrev = $missing_tz_abbrs[$tz]; + else { - $msk_offset = intval($tz_abbrev) - 3; - $msk_offset = !empty($msk_offset) ? sprintf('%+0d', $msk_offset) : ''; - $tz_abbrev = 'MSK' . $msk_offset; + // Russia likes to experiment with time zones + $tz_location = timezone_location_get(timezone_open($row['timezone'])); + if ($tz_location['country_code'] == 'RU') + { + $msk_offset = intval($tz_abbrev) - 3; + $msk_offset = !empty($msk_offset) ? sprintf('%+0d', $msk_offset) : ''; + $tz_abbrev = 'MSK' . $msk_offset; + } } // Still no good? We'll just mark it as a UTC offset @@ -1644,7 +1691,7 @@ function getUserTimezone($id_member = null) if (is_null($id_member) && $user_info['is_guest'] == false) $id_member = $context['user']['id']; - + //check if the cache got the data if (isset($id_member) && isset($member_cache[$id_member])) { @@ -1670,7 +1717,7 @@ function getUserTimezone($id_member = null) if (isset($id_member)) $member_cache[$id_member] = $timezone; - + return $timezone; } diff --git a/Sources/Subs.php b/Sources/Subs.php index 5ac3053dd0..e1680e4e77 100644 --- a/Sources/Subs.php +++ b/Sources/Subs.php @@ -3676,7 +3676,7 @@ function getAttachmentFilename($filename, $attachment_id, $dir = null, $new = fa // Just make up a nice hash... if ($new) return sha1(md5($filename . time()) . mt_rand()); - + // Just make sure that attachment id is only a int $attachment_id = (int) $attachment_id; @@ -4950,6 +4950,7 @@ function smf_list_timezones($when = 'now') 'Asia/Rangoon' => 'Yangon/Rangoon', 'Indian/Christmas' => 'Christmas Island', 'Antarctica/DumontDUrville' => 'Dumont D\'Urville Station', + 'Antarctica/Vostok' => 'Vostok Station', 'Australia/Lord_Howe' => 'Lord Howe Island', 'Pacific/Guadalcanal' => 'Solomon Islands', 'Pacific/Norfolk' => 'Norfolk Island', @@ -4985,18 +4986,65 @@ function smf_list_timezones($when = 'now') // There are a handful of time zones that PHP doesn't know the proper shortform for. Fix 'em if we can. if (strspn($tzinfo[0]['abbr'], '+-') > 0) { - $tz_location = timezone_location_get(timezone_open($tzid)); - - // Kazakstan - if ($tz_location['country_code'] == 'KZ') - $tzinfo[0]['abbr'] = str_replace(array('+05', '+06'), array('AQTT', 'ALMT'), $tzinfo[0]['abbr']); + $missing_tz_abbrs = array( + 'Antarctica/Casey' => 'CAST', + 'Antarctica/Davis' => 'DAVT', + 'Antarctica/DumontDUrville' => 'DDUT', + 'Antarctica/Mawson' => 'MAWT', + 'Antarctica/Rothera' => 'ART', + 'Antarctica/Syowa' => 'SYOT', + 'Antarctica/Troll' => 'CET', + 'Antarctica/Vostok' => 'VOST', + 'Asia/Almaty' => 'ALMT', + 'Asia/Anadyr' => 'ANAT', + 'Asia/Aqtau' => 'ORAT', + 'Asia/Aqtobe' => 'AQTT', + 'Asia/Ashgabat' => 'TMT', + 'Asia/Baku' => 'AZT', + 'Asia/Bishkek' => 'KGT', + 'Asia/Chita' => 'YAKT', + 'Asia/Colombo' => 'IST', + 'Asia/Dushanbe' => 'TJT', + 'Asia/Irkutsk' => 'IRKT', + 'Asia/Kamchatka' => 'PETT', + 'Asia/Khandyga' => 'YAKT', + 'Asia/Krasnoyarsk' => 'KRAT', + 'Asia/Magadan' => 'MAGT', + 'Asia/Novokuznetsk' => 'KRAT', + 'Asia/Novosibirsk' => 'NOVT', + 'Asia/Omsk' => 'OMST', + 'Asia/Oral' => 'ORAT', + 'Asia/Qyzylorda' => 'QYZT', + 'Asia/Sakhalin' => 'SAKT', + 'Asia/Samarkand' => 'UZT', + 'Asia/Srednekolymsk' => 'SRET', + 'Asia/Tashkent' => 'UZT', + 'Asia/Tbilisi' => 'GET', + 'Asia/Ust-Nera' => 'VLAT', + 'Asia/Vladivostok' => 'VLAT', + 'Asia/Yakutsk' => 'YAKT', + 'Asia/Yekaterinburg' => 'YEKT', + 'Asia/Yerevan' => 'AMT', + 'Europe/Istanbul' => 'TRT', + 'Europe/Kirov' => 'MSK', + 'Europe/Minsk' => 'MSK', + 'Europe/Samara' => 'SAMT', + 'Europe/Volgograd' => 'MSK', + 'Indian/Kerguelen' => 'TFT', + ); - // Russia likes to experiment with time zones - if ($tz_location['country_code'] == 'RU') + if (!empty($missing_tz_abbrs[$tzid])) + $tzinfo[0]['abbr'] = $missing_tz_abbrs[$tzid]; + else { - $msk_offset = intval($tzinfo[0]['abbr']) - 3; - $msk_offset = !empty($msk_offset) ? sprintf('%+0d', $msk_offset) : ''; - $tzinfo[0]['abbr'] = 'MSK' . $msk_offset; + // Russia likes to experiment with time zones + $tz_location = timezone_location_get(timezone_open($tzid)); + if ($tz_location['country_code'] == 'RU') + { + $msk_offset = intval($tzinfo[0]['abbr']) - 3; + $msk_offset = !empty($msk_offset) ? sprintf('%+0d', $msk_offset) : ''; + $tzinfo[0]['abbr'] = 'MSK' . $msk_offset; + } } // Still no good? We'll just mark it as a UTC offset From 10d6062142430767e1b1dadd7f5beae8897bc7a8 Mon Sep 17 00:00:00 2001 From: Jon Stovell Date: Fri, 24 Mar 2017 21:54:37 -0600 Subject: [PATCH 2/9] Only provide missing abbrevs for stable time zones with no DST (so, not Russia) Signed-off-by: Jon Stovell --- Sources/Subs-Calendar.php | 30 ++++++------------------------ Sources/Subs.php | 30 ++++++------------------------ 2 files changed, 12 insertions(+), 48 deletions(-) diff --git a/Sources/Subs-Calendar.php b/Sources/Subs-Calendar.php index b8933bc708..be1c35d84b 100644 --- a/Sources/Subs-Calendar.php +++ b/Sources/Subs-Calendar.php @@ -1609,6 +1609,7 @@ function buildEventDatetimes($row) // There are a handful of time zones that PHP doesn't know the abbreviation for. Fix 'em if we can. if (strspn($tz_abbrev, '+-') > 0) { + // To get on this list, a time zone must be historically stable and must not observe daylight saving time $missing_tz_abbrs = array( 'Antarctica/Casey' => 'CAST', 'Antarctica/Davis' => 'DAVT', @@ -1616,43 +1617,22 @@ function buildEventDatetimes($row) 'Antarctica/Mawson' => 'MAWT', 'Antarctica/Rothera' => 'ART', 'Antarctica/Syowa' => 'SYOT', - 'Antarctica/Troll' => 'CET', 'Antarctica/Vostok' => 'VOST', 'Asia/Almaty' => 'ALMT', - 'Asia/Anadyr' => 'ANAT', 'Asia/Aqtau' => 'ORAT', 'Asia/Aqtobe' => 'AQTT', 'Asia/Ashgabat' => 'TMT', - 'Asia/Baku' => 'AZT', 'Asia/Bishkek' => 'KGT', - 'Asia/Chita' => 'YAKT', 'Asia/Colombo' => 'IST', 'Asia/Dushanbe' => 'TJT', - 'Asia/Irkutsk' => 'IRKT', - 'Asia/Kamchatka' => 'PETT', - 'Asia/Khandyga' => 'YAKT', - 'Asia/Krasnoyarsk' => 'KRAT', - 'Asia/Magadan' => 'MAGT', - 'Asia/Novokuznetsk' => 'KRAT', - 'Asia/Novosibirsk' => 'NOVT', - 'Asia/Omsk' => 'OMST', 'Asia/Oral' => 'ORAT', 'Asia/Qyzylorda' => 'QYZT', - 'Asia/Sakhalin' => 'SAKT', 'Asia/Samarkand' => 'UZT', - 'Asia/Srednekolymsk' => 'SRET', 'Asia/Tashkent' => 'UZT', 'Asia/Tbilisi' => 'GET', - 'Asia/Ust-Nera' => 'VLAT', - 'Asia/Vladivostok' => 'VLAT', - 'Asia/Yakutsk' => 'YAKT', - 'Asia/Yekaterinburg' => 'YEKT', 'Asia/Yerevan' => 'AMT', 'Europe/Istanbul' => 'TRT', - 'Europe/Kirov' => 'MSK', 'Europe/Minsk' => 'MSK', - 'Europe/Samara' => 'SAMT', - 'Europe/Volgograd' => 'MSK', 'Indian/Kerguelen' => 'TFT', ); @@ -1665,14 +1645,16 @@ function buildEventDatetimes($row) if ($tz_location['country_code'] == 'RU') { $msk_offset = intval($tz_abbrev) - 3; - $msk_offset = !empty($msk_offset) ? sprintf('%+0d', $msk_offset) : ''; - $tz_abbrev = 'MSK' . $msk_offset; + $tz_abbrev = 'MSK' . (!empty($msk_offset) ? sprintf('%+0d', $msk_offset) : ''); } } // Still no good? We'll just mark it as a UTC offset if (strspn($tz_abbrev, '+-') > 0) - $tz_abbrev = 'UTC' . $tz_abbrev; + { + $tz_abbrev = intval($tz_abbrev); + $tz_abbrev = 'UTC' . (!empty($tz_abbrev) ? sprintf('%+0d', $tz_abbrev) : ''); + } } return array($start, $end, $allday, $span, $tz, $tz_abbrev); diff --git a/Sources/Subs.php b/Sources/Subs.php index e1680e4e77..28ad64ba14 100644 --- a/Sources/Subs.php +++ b/Sources/Subs.php @@ -4986,6 +4986,7 @@ function smf_list_timezones($when = 'now') // There are a handful of time zones that PHP doesn't know the proper shortform for. Fix 'em if we can. if (strspn($tzinfo[0]['abbr'], '+-') > 0) { + // To get on this list, a time zone must be historically stable and must not observe daylight saving time $missing_tz_abbrs = array( 'Antarctica/Casey' => 'CAST', 'Antarctica/Davis' => 'DAVT', @@ -4993,43 +4994,22 @@ function smf_list_timezones($when = 'now') 'Antarctica/Mawson' => 'MAWT', 'Antarctica/Rothera' => 'ART', 'Antarctica/Syowa' => 'SYOT', - 'Antarctica/Troll' => 'CET', 'Antarctica/Vostok' => 'VOST', 'Asia/Almaty' => 'ALMT', - 'Asia/Anadyr' => 'ANAT', 'Asia/Aqtau' => 'ORAT', 'Asia/Aqtobe' => 'AQTT', 'Asia/Ashgabat' => 'TMT', - 'Asia/Baku' => 'AZT', 'Asia/Bishkek' => 'KGT', - 'Asia/Chita' => 'YAKT', 'Asia/Colombo' => 'IST', 'Asia/Dushanbe' => 'TJT', - 'Asia/Irkutsk' => 'IRKT', - 'Asia/Kamchatka' => 'PETT', - 'Asia/Khandyga' => 'YAKT', - 'Asia/Krasnoyarsk' => 'KRAT', - 'Asia/Magadan' => 'MAGT', - 'Asia/Novokuznetsk' => 'KRAT', - 'Asia/Novosibirsk' => 'NOVT', - 'Asia/Omsk' => 'OMST', 'Asia/Oral' => 'ORAT', 'Asia/Qyzylorda' => 'QYZT', - 'Asia/Sakhalin' => 'SAKT', 'Asia/Samarkand' => 'UZT', - 'Asia/Srednekolymsk' => 'SRET', 'Asia/Tashkent' => 'UZT', 'Asia/Tbilisi' => 'GET', - 'Asia/Ust-Nera' => 'VLAT', - 'Asia/Vladivostok' => 'VLAT', - 'Asia/Yakutsk' => 'YAKT', - 'Asia/Yekaterinburg' => 'YEKT', 'Asia/Yerevan' => 'AMT', 'Europe/Istanbul' => 'TRT', - 'Europe/Kirov' => 'MSK', 'Europe/Minsk' => 'MSK', - 'Europe/Samara' => 'SAMT', - 'Europe/Volgograd' => 'MSK', 'Indian/Kerguelen' => 'TFT', ); @@ -5042,14 +5022,16 @@ function smf_list_timezones($when = 'now') if ($tz_location['country_code'] == 'RU') { $msk_offset = intval($tzinfo[0]['abbr']) - 3; - $msk_offset = !empty($msk_offset) ? sprintf('%+0d', $msk_offset) : ''; - $tzinfo[0]['abbr'] = 'MSK' . $msk_offset; + $tzinfo[0]['abbr'] = 'MSK' . (!empty($msk_offset) ? sprintf('%+0d', $msk_offset) : ''); } } // Still no good? We'll just mark it as a UTC offset if (strspn($tzinfo[0]['abbr'], '+-') > 0) - $tzinfo[0]['abbr'] = 'UTC' . $tzinfo[0]['abbr']; + { + $tz_abbrev = intval($tzinfo[0]['abbr']); + $tzinfo[0]['abbr'] = 'UTC' . (!empty($tz_abbrev) ? sprintf('%+0d', $tz_abbrev) : ''); + } } $tzkey = serialize($tzinfo); From 942dfb7d89f3c29aaf734b2d7c570e75e45e8dd4 Mon Sep 17 00:00:00 2001 From: Jon Stovell Date: Sat, 22 Apr 2017 02:54:11 -0600 Subject: [PATCH 3/9] Ensures all tz abbrevs are formatted nicely; consolidates code. Signed-off-by: Jon Stovell --- Sources/Calendar.php | 2 +- Sources/Post.php | 4 +- Sources/Subs-Calendar.php | 53 +---------------- Sources/Subs.php | 117 ++++++++++++++++++++++---------------- 4 files changed, 71 insertions(+), 105 deletions(-) diff --git a/Sources/Calendar.php b/Sources/Calendar.php index 4f03ec23dd..bec431e9d8 100644 --- a/Sources/Calendar.php +++ b/Sources/Calendar.php @@ -451,7 +451,7 @@ function CalendarPost() if (!in_array($context['event']['tz'], array_keys($context['all_timezones']))) { $d = date_create($context['event']['tz']); - $context['all_timezones'] = array($context['event']['tz'] => date_format($d, 'T') . ' - ' . $context['event']['tz'] . ' [UTC' . date_format($d, 'P') . ']') + $context['all_timezones']; + $context['all_timezones'] = array($context['event']['tz'] => fix_tz_abbrev($context['event']['tz'], date_format($d, 'T')) . ' - ' . $context['event']['tz'] . ' [UTC' . date_format($d, 'P') . ']') + $context['all_timezones']; } // Get list of boards that can be posted in. diff --git a/Sources/Post.php b/Sources/Post.php index cff7bf822c..0d1b7bb344 100644 --- a/Sources/Post.php +++ b/Sources/Post.php @@ -192,7 +192,7 @@ function Post($post_errors = array()) if (empty ($_REQUEST['message']) && empty ($_REQUEST['preview'])) { unset($_SESSION['already_attached']); } - + // Don't allow a post if it's locked and you aren't all powerful. if ($locked && !allowedTo('moderate_board')) fatal_lang_error('topic_locked', false); @@ -331,7 +331,7 @@ function Post($post_errors = array()) if (!in_array($context['event']['tz'], array_keys($context['all_timezones']))) { $d = date_create($context['event']['tz']); - $context['all_timezones'] = array($context['event']['tz'] => date_format($d, 'T') . ' - ' . $context['event']['tz'] . ' [UTC' . date_format($d, 'P') . ']') + $context['all_timezones']; + $context['all_timezones'] = array($context['event']['tz'] => fix_tz_abbrev($context['event']['tz'], date_format($d, 'T')) . ' - ' . $context['event']['tz'] . ' [UTC' . date_format($d, 'P') . ']') + $context['all_timezones']; } loadCSSFile('jquery-ui.datepicker.css', array('defer' => false), 'smf_datepicker'); diff --git a/Sources/Subs-Calendar.php b/Sources/Subs-Calendar.php index be1c35d84b..6c5ca98cf1 100644 --- a/Sources/Subs-Calendar.php +++ b/Sources/Subs-Calendar.php @@ -1604,58 +1604,7 @@ function buildEventDatetimes($row) // The time zone identifier (e.g. 'Europe/London') and abbreviation (e.g. 'GMT') $tz = date_format($start_object, 'e'); - $tz_abbrev = date_format($start_object, 'T'); - - // There are a handful of time zones that PHP doesn't know the abbreviation for. Fix 'em if we can. - if (strspn($tz_abbrev, '+-') > 0) - { - // To get on this list, a time zone must be historically stable and must not observe daylight saving time - $missing_tz_abbrs = array( - 'Antarctica/Casey' => 'CAST', - 'Antarctica/Davis' => 'DAVT', - 'Antarctica/DumontDUrville' => 'DDUT', - 'Antarctica/Mawson' => 'MAWT', - 'Antarctica/Rothera' => 'ART', - 'Antarctica/Syowa' => 'SYOT', - 'Antarctica/Vostok' => 'VOST', - 'Asia/Almaty' => 'ALMT', - 'Asia/Aqtau' => 'ORAT', - 'Asia/Aqtobe' => 'AQTT', - 'Asia/Ashgabat' => 'TMT', - 'Asia/Bishkek' => 'KGT', - 'Asia/Colombo' => 'IST', - 'Asia/Dushanbe' => 'TJT', - 'Asia/Oral' => 'ORAT', - 'Asia/Qyzylorda' => 'QYZT', - 'Asia/Samarkand' => 'UZT', - 'Asia/Tashkent' => 'UZT', - 'Asia/Tbilisi' => 'GET', - 'Asia/Yerevan' => 'AMT', - 'Europe/Istanbul' => 'TRT', - 'Europe/Minsk' => 'MSK', - 'Indian/Kerguelen' => 'TFT', - ); - - if (!empty($missing_tz_abbrs[$tz])) - $tz_abbrev = $missing_tz_abbrs[$tz]; - else - { - // Russia likes to experiment with time zones - $tz_location = timezone_location_get(timezone_open($row['timezone'])); - if ($tz_location['country_code'] == 'RU') - { - $msk_offset = intval($tz_abbrev) - 3; - $tz_abbrev = 'MSK' . (!empty($msk_offset) ? sprintf('%+0d', $msk_offset) : ''); - } - } - - // Still no good? We'll just mark it as a UTC offset - if (strspn($tz_abbrev, '+-') > 0) - { - $tz_abbrev = intval($tz_abbrev); - $tz_abbrev = 'UTC' . (!empty($tz_abbrev) ? sprintf('%+0d', $tz_abbrev) : ''); - } - } + $tz_abbrev = fix_tz_abbrev($row['timezone'], date_format($start_object, 'T')); return array($start, $end, $allday, $span, $tz, $tz_abbrev); } diff --git a/Sources/Subs.php b/Sources/Subs.php index 28ad64ba14..61bdcdb6de 100644 --- a/Sources/Subs.php +++ b/Sources/Subs.php @@ -4983,56 +4983,7 @@ function smf_list_timezones($when = 'now') // First, get the set of transition rules for this tzid $tzinfo = timezone_transitions_get(timezone_open($tzid), $when, $later); - // There are a handful of time zones that PHP doesn't know the proper shortform for. Fix 'em if we can. - if (strspn($tzinfo[0]['abbr'], '+-') > 0) - { - // To get on this list, a time zone must be historically stable and must not observe daylight saving time - $missing_tz_abbrs = array( - 'Antarctica/Casey' => 'CAST', - 'Antarctica/Davis' => 'DAVT', - 'Antarctica/DumontDUrville' => 'DDUT', - 'Antarctica/Mawson' => 'MAWT', - 'Antarctica/Rothera' => 'ART', - 'Antarctica/Syowa' => 'SYOT', - 'Antarctica/Vostok' => 'VOST', - 'Asia/Almaty' => 'ALMT', - 'Asia/Aqtau' => 'ORAT', - 'Asia/Aqtobe' => 'AQTT', - 'Asia/Ashgabat' => 'TMT', - 'Asia/Bishkek' => 'KGT', - 'Asia/Colombo' => 'IST', - 'Asia/Dushanbe' => 'TJT', - 'Asia/Oral' => 'ORAT', - 'Asia/Qyzylorda' => 'QYZT', - 'Asia/Samarkand' => 'UZT', - 'Asia/Tashkent' => 'UZT', - 'Asia/Tbilisi' => 'GET', - 'Asia/Yerevan' => 'AMT', - 'Europe/Istanbul' => 'TRT', - 'Europe/Minsk' => 'MSK', - 'Indian/Kerguelen' => 'TFT', - ); - - if (!empty($missing_tz_abbrs[$tzid])) - $tzinfo[0]['abbr'] = $missing_tz_abbrs[$tzid]; - else - { - // Russia likes to experiment with time zones - $tz_location = timezone_location_get(timezone_open($tzid)); - if ($tz_location['country_code'] == 'RU') - { - $msk_offset = intval($tzinfo[0]['abbr']) - 3; - $tzinfo[0]['abbr'] = 'MSK' . (!empty($msk_offset) ? sprintf('%+0d', $msk_offset) : ''); - } - } - - // Still no good? We'll just mark it as a UTC offset - if (strspn($tzinfo[0]['abbr'], '+-') > 0) - { - $tz_abbrev = intval($tzinfo[0]['abbr']); - $tzinfo[0]['abbr'] = 'UTC' . (!empty($tz_abbrev) ? sprintf('%+0d', $tz_abbrev) : ''); - } - } + $tzinfo[0]['abbr'] = fix_tz_abbrev($tzid, $tzinfo[0]['abbr']); $tzkey = serialize($tzinfo); @@ -5080,6 +5031,72 @@ function smf_list_timezones($when = 'now') return $timezones; } +/** + * Reformats certain time zone abbreviations to look better. + * + * Some of PHP's time zone abbreviations are just numerical offsets from UTC, e.g. '+04' + * These look weird and are kind of useless, so we make them look better. + * + * @param string $tzid The Olsen time zome identifier for a time zone. + * @param string $tz_abbrev The abbreviation PHP provided for this time zone. + * @return string The fixed version of $tz_abbrev. + */ +function fix_tz_abbrev($tzid, $tz_abbrev) +{ + // Is this abbreviation just a numerical offset? + if (strspn($tz_abbrev, '+-') > 0) + { + // To get on this list, a time zone must be historically stable and must not observe daylight saving time + $missing_tz_abbrs = array( + 'Antarctica/Casey' => 'CAST', + 'Antarctica/Davis' => 'DAVT', + 'Antarctica/DumontDUrville' => 'DDUT', + 'Antarctica/Mawson' => 'MAWT', + 'Antarctica/Rothera' => 'ART', + 'Antarctica/Syowa' => 'SYOT', + 'Antarctica/Vostok' => 'VOST', + 'Asia/Almaty' => 'ALMT', + 'Asia/Aqtau' => 'ORAT', + 'Asia/Aqtobe' => 'AQTT', + 'Asia/Ashgabat' => 'TMT', + 'Asia/Bishkek' => 'KGT', + 'Asia/Colombo' => 'IST', + 'Asia/Dushanbe' => 'TJT', + 'Asia/Oral' => 'ORAT', + 'Asia/Qyzylorda' => 'QYZT', + 'Asia/Samarkand' => 'UZT', + 'Asia/Tashkent' => 'UZT', + 'Asia/Tbilisi' => 'GET', + 'Asia/Yerevan' => 'AMT', + 'Europe/Istanbul' => 'TRT', + 'Europe/Minsk' => 'MSK', + 'Indian/Kerguelen' => 'TFT', + ); + + if (!empty($missing_tz_abbrs[$tzid])) + $tz_abbrev = $missing_tz_abbrs[$tzid]; + else + { + // Russia likes to experiment with time zones often, and names them as offsets from Moscow + $tz_location = timezone_location_get(timezone_open($tzid)); + if ($tz_location['country_code'] == 'RU') + { + $msk_offset = intval($tz_abbrev) - 3; + $tz_abbrev = 'MSK' . (!empty($msk_offset) ? sprintf('%+0d', $msk_offset) : ''); + } + } + + // Still no good? We'll just mark it as a UTC offset + if (strspn($tz_abbrev, '+-') > 0) + { + $tz_abbrev = intval($tz_abbrev); + $tz_abbrev = 'UTC' . (!empty($tz_abbrev) ? sprintf('%+0d', $tz_abbrev) : ''); + } + } + + return $tz_abbrev; +} + /** * @param string $ip_address An IP address in IPv4, IPv6 or decimal notation * @return binary The IP address in binary or false From 9cf73bebcf304c60b4a02d0343f597e7e626e9bb Mon Sep 17 00:00:00 2001 From: Jon Stovell Date: Tue, 25 Apr 2017 14:51:21 -0600 Subject: [PATCH 4/9] Fixes a bug with getting UTC offset values for time zones Signed-off-by: Jon Stovell --- Sources/Subs.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Sources/Subs.php b/Sources/Subs.php index 61bdcdb6de..9f40c4b909 100644 --- a/Sources/Subs.php +++ b/Sources/Subs.php @@ -4904,14 +4904,14 @@ function smf_list_timezones($when = 'now') else $when = time(); - // We'll need this too - $later = (int) date_format(date_add(date_create('@' . $when), date_interval_create_from_date_string('1 year')), 'U'); + // We'll need these too + $date_when = date_create('@' . $when); + $later = (int) date_format(date_add($date_when, date_interval_create_from_date_string('1 year')), 'U'); // Prefer and give custom descriptions for these time zones // If the description is left empty, it will be filled in with the names of matching cities $timezone_descriptions = array( - 'America/Adak' => 'Hawaii-Aleutian', - 'Pacific/Honolulu' => 'Hawaii', + 'America/Adak' => 'Aleutian Islands', 'Pacific/Marquesas' => 'Marquesas Islands', 'Pacific/Gambier' => 'Gambier Islands', 'America/Anchorage' => 'Alaska', @@ -5011,6 +5011,8 @@ function smf_list_timezones($when = 'now') { $tzinfo = unserialize($tzkey); + date_timezone_set($date_when, timezone_open($tzvalue['tzid'])); + if (!empty($timezone_descriptions[$tzvalue['tzid']])) $desc = $timezone_descriptions[$tzvalue['tzid']]; else @@ -5019,7 +5021,7 @@ function smf_list_timezones($when = 'now') if (isset($priority_zones[$tzkey])) $priority_timezones[$tzvalue['tzid']] = $tzinfo[0]['abbr'] . ' - ' . $desc . ' [UTC' . date_format(date_create($tzvalue['tzid']), 'P') . ']'; else - $timezones[$tzvalue['tzid']] = $tzinfo[0]['abbr'] . ' - ' . $desc . ' [UTC' . date_format(date_create($tzvalue['tzid']), 'P') . ']'; + $timezones[$tzvalue['tzid']] = $tzinfo[0]['abbr'] . ' - ' . $desc . ' [UTC' . date_format($date_when, 'P') . ']'; } $timezones = array_merge( From 7954e3b1873c1e94c3f4f572568a3236d3a59a59 Mon Sep 17 00:00:00 2001 From: Jon Stovell Date: Tue, 25 Apr 2017 14:53:26 -0600 Subject: [PATCH 5/9] Sorts time zones by offset and longitude (more stable & intuitive) Signed-off-by: Jon Stovell --- Sources/Subs.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Sources/Subs.php b/Sources/Subs.php index 9f40c4b909..96c5bccf48 100644 --- a/Sources/Subs.php +++ b/Sources/Subs.php @@ -4980,13 +4980,18 @@ function smf_list_timezones($when = 'now') if ($tzid == 'UTC') continue; + $tz = timezone_open($tzid); + // First, get the set of transition rules for this tzid - $tzinfo = timezone_transitions_get(timezone_open($tzid), $when, $later); + $tzinfo = timezone_transitions_get($tz, $when, $later); $tzinfo[0]['abbr'] = fix_tz_abbrev($tzid, $tzinfo[0]['abbr']); $tzkey = serialize($tzinfo); + // Next, get the geographic info for this tzid + $tzgeo = timezone_location_get($tz); + // Don't overwrite our preferred tzids if (empty($zones[$tzkey]['tzid'])) $zones[$tzkey]['tzid'] = $tzid; @@ -4999,10 +5004,11 @@ function smf_list_timezones($when = 'now') $tzid_parts = explode('/', $tzid); $zones[$tzkey]['locations'][] = str_replace(array('St_', '_'), array('St. ', ' '), array_pop($tzid_parts)); $offsets[$tzkey] = $tzinfo[0]['offset']; + $longitudes[$tzkey] = empty($longitudes[$tzkey]) ? $tzgeo['longitude'] : $longitudes[$tzkey]; } - // Sort by offset - array_multisort($offsets, SORT_ASC, $zones); + // Sort by offset then longitude + array_multisort($offsets, SORT_ASC, SORT_NUMERIC, $longitudes, SORT_ASC, SORT_NUMERIC, $zones); // Build the final array of formatted values $priority_timezones = array(); @@ -5021,7 +5027,7 @@ function smf_list_timezones($when = 'now') if (isset($priority_zones[$tzkey])) $priority_timezones[$tzvalue['tzid']] = $tzinfo[0]['abbr'] . ' - ' . $desc . ' [UTC' . date_format(date_create($tzvalue['tzid']), 'P') . ']'; else - $timezones[$tzvalue['tzid']] = $tzinfo[0]['abbr'] . ' - ' . $desc . ' [UTC' . date_format($date_when, 'P') . ']'; + $timezones[$tzvalue['tzid']] = $tzinfo[0]['abbr'] . ' - ' . $desc . ' [UTC' . date_format($date_when, 'P') . '] (' . $longitudes[$tzkey] . ')'; } $timezones = array_merge( From 0c59c244783b4793ee03ac1ea4af10bfab203192 Mon Sep 17 00:00:00 2001 From: Jon Stovell Date: Tue, 25 Apr 2017 15:04:33 -0600 Subject: [PATCH 6/9] That's not supposed to be there Signed-off-by: Jon Stovell --- Sources/Subs.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Subs.php b/Sources/Subs.php index 96c5bccf48..a4f3b308db 100644 --- a/Sources/Subs.php +++ b/Sources/Subs.php @@ -5027,7 +5027,7 @@ function smf_list_timezones($when = 'now') if (isset($priority_zones[$tzkey])) $priority_timezones[$tzvalue['tzid']] = $tzinfo[0]['abbr'] . ' - ' . $desc . ' [UTC' . date_format(date_create($tzvalue['tzid']), 'P') . ']'; else - $timezones[$tzvalue['tzid']] = $tzinfo[0]['abbr'] . ' - ' . $desc . ' [UTC' . date_format($date_when, 'P') . '] (' . $longitudes[$tzkey] . ')'; + $timezones[$tzvalue['tzid']] = $tzinfo[0]['abbr'] . ' - ' . $desc . ' [UTC' . date_format($date_when, 'P') . ']'; } $timezones = array_merge( From 4adae3daf8b9a87aa6283d8d6ef61beb2e7d4b93 Mon Sep 17 00:00:00 2001 From: Jon Stovell Date: Tue, 25 Apr 2017 15:20:26 -0600 Subject: [PATCH 7/9] Fixes the bug getting UTC offsets for priority time zones, too. Signed-off-by: Jon Stovell --- Sources/Subs.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Subs.php b/Sources/Subs.php index a4f3b308db..4b3cb51e51 100644 --- a/Sources/Subs.php +++ b/Sources/Subs.php @@ -5025,7 +5025,7 @@ function smf_list_timezones($when = 'now') $desc = implode(', ', array_unique($tzvalue['locations'])); if (isset($priority_zones[$tzkey])) - $priority_timezones[$tzvalue['tzid']] = $tzinfo[0]['abbr'] . ' - ' . $desc . ' [UTC' . date_format(date_create($tzvalue['tzid']), 'P') . ']'; + $priority_timezones[$tzvalue['tzid']] = $tzinfo[0]['abbr'] . ' - ' . $desc . ' [UTC' . date_format($date_when, 'P') . ']'; else $timezones[$tzvalue['tzid']] = $tzinfo[0]['abbr'] . ' - ' . $desc . ' [UTC' . date_format($date_when, 'P') . ']'; } From 0cf8975390e2a177b2fc1290a5ba87bb914ed363 Mon Sep 17 00:00:00 2001 From: Jon Stovell Date: Tue, 25 Apr 2017 15:55:03 -0600 Subject: [PATCH 8/9] Fixes a bug where incorrect times were loaded when editing an event Signed-off-by: Jon Stovell --- Sources/Calendar.php | 4 ++-- Sources/Post.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/Calendar.php b/Sources/Calendar.php index 4f03ec23dd..1318fc028d 100644 --- a/Sources/Calendar.php +++ b/Sources/Calendar.php @@ -439,8 +439,8 @@ function CalendarPost() // Otherwise, just adjust these to look nice on the input form else { - $context['event']['start_time'] = timeformat(strtotime($context['event']['start_iso_gmdate']), $time_string); - $context['event']['end_time'] = timeformat(strtotime($context['event']['end_iso_gmdate']), $time_string); + $context['event']['start_time'] = $context['event']['start_time_orig']; + $context['event']['end_time'] = $context['event']['end_time_orig']; } // Need this so the user can select a timezone for the event. diff --git a/Sources/Post.php b/Sources/Post.php index 9a04180f49..5cbe48d177 100644 --- a/Sources/Post.php +++ b/Sources/Post.php @@ -192,7 +192,7 @@ function Post($post_errors = array()) if (empty ($_REQUEST['message']) && empty ($_REQUEST['preview'])) { unset($_SESSION['already_attached']); } - + // Don't allow a post if it's locked and you aren't all powerful. if ($locked && !allowedTo('moderate_board')) fatal_lang_error('topic_locked', false); @@ -319,8 +319,8 @@ function Post($post_errors = array()) // Otherwise, just adjust these to look nice on the input form else { - $context['event']['start_time'] = timeformat(strtotime($context['event']['start_iso_gmdate']), $time_string); - $context['event']['end_time'] = timeformat(strtotime($context['event']['end_iso_gmdate']), $time_string); + $context['event']['start_time'] = $context['event']['start_time_orig']; + $context['event']['end_time'] = $context['event']['end_time_orig']; } // Need this so the user can select a timezone for the event. From 7a793abca4271b6d87c9c26e77df0c430a75703c Mon Sep 17 00:00:00 2001 From: Jon Stovell Date: Tue, 25 Apr 2017 16:11:00 -0600 Subject: [PATCH 9/9] Gives the correct UTC offset for time zones not in our standard list Signed-off-by: Jon Stovell --- Sources/Calendar.php | 2 +- Sources/Post.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Calendar.php b/Sources/Calendar.php index ab427e0cd5..5f2ddf782b 100644 --- a/Sources/Calendar.php +++ b/Sources/Calendar.php @@ -450,7 +450,7 @@ function CalendarPost() // If the event's timezone is not in SMF's standard list of time zones, prepend it to the list if (!in_array($context['event']['tz'], array_keys($context['all_timezones']))) { - $d = date_create($context['event']['tz']); + $d = date_create($context['event']['start_datetime'] . ' ' . $context['event']['tz']); $context['all_timezones'] = array($context['event']['tz'] => fix_tz_abbrev($context['event']['tz'], date_format($d, 'T')) . ' - ' . $context['event']['tz'] . ' [UTC' . date_format($d, 'P') . ']') + $context['all_timezones']; } diff --git a/Sources/Post.php b/Sources/Post.php index e3b8cf8522..f64ee0febe 100644 --- a/Sources/Post.php +++ b/Sources/Post.php @@ -330,7 +330,7 @@ function Post($post_errors = array()) // If the event's timezone is not in SMF's standard list of time zones, prepend it to the list if (!in_array($context['event']['tz'], array_keys($context['all_timezones']))) { - $d = date_create($context['event']['tz']); + $d = date_create($context['event']['start_datetime'] . ' ' . $context['event']['tz']); $context['all_timezones'] = array($context['event']['tz'] => fix_tz_abbrev($context['event']['tz'], date_format($d, 'T')) . ' - ' . $context['event']['tz'] . ' [UTC' . date_format($d, 'P') . ']') + $context['all_timezones']; }