Skip to content

Commit

Permalink
Merge pull request #3990 from Sesquipedalian/tz_fallback
Browse files Browse the repository at this point in the history
Improvements to smf_timezone_list, etc.
  • Loading branch information
Oldiesmann authored May 18, 2017
2 parents 2aadb5f + 7a793ab commit 9b1f3df
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 61 deletions.
8 changes: 4 additions & 4 deletions Sources/Calendar.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -450,8 +450,8 @@ 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']);
$context['all_timezones'] = array($context['event']['tz'] => date_format($d, 'T') . ' - ' . $context['event']['tz'] . ' [UTC' . date_format($d, 'P') . ']') + $context['all_timezones'];
$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'];
}

// Get list of boards that can be posted in.
Expand Down
8 changes: 4 additions & 4 deletions Sources/Post.php
Original file line number Diff line number Diff line change
Expand Up @@ -318,8 +318,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.
Expand All @@ -329,8 +329,8 @@ 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']);
$context['all_timezones'] = array($context['event']['tz'] => date_format($d, 'T') . ' - ' . $context['event']['tz'] . ' [UTC' . date_format($d, 'P') . ']') + $context['all_timezones'];
$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'];
}

loadCSSFile('jquery-ui.datepicker.css', array('defer' => false), 'smf_datepicker');
Expand Down
24 changes: 1 addition & 23 deletions Sources/Subs-Calendar.php
Original file line number Diff line number Diff line change
Expand Up @@ -1591,29 +1591,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)
{
$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);

// Russia likes to experiment with time zones
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
if (strspn($tz_abbrev, '+-') > 0)
$tz_abbrev = 'UTC' . $tz_abbrev;
}
$tz_abbrev = fix_tz_abbrev($row['timezone'], date_format($start_object, 'T'));

return array($start, $end, $allday, $span, $tz, $tz_abbrev);
}
Expand Down
115 changes: 85 additions & 30 deletions Sources/Subs.php
Original file line number Diff line number Diff line change
Expand Up @@ -4932,14 +4932,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',
Expand Down Expand Up @@ -4978,6 +4978,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',
Expand Down Expand Up @@ -5007,33 +5008,18 @@ function smf_list_timezones($when = 'now')
if ($tzid == 'UTC')
continue;

// First, get the set of transition rules for this tzid
$tzinfo = timezone_transitions_get(timezone_open($tzid), $when, $later);
$tz = timezone_open($tzid);

// 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));
// First, get the set of transition rules for this tzid
$tzinfo = timezone_transitions_get($tz, $when, $later);

// Kazakstan
if ($tz_location['country_code'] == 'KZ')
$tzinfo[0]['abbr'] = str_replace(array('+05', '+06'), array('AQTT', 'ALMT'), $tzinfo[0]['abbr']);

// Russia likes to experiment with time zones
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
if (strspn($tzinfo[0]['abbr'], '+-') > 0)
$tzinfo[0]['abbr'] = 'UTC' . $tzinfo[0]['abbr'];
}
$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;
Expand All @@ -5046,10 +5032,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();
Expand All @@ -5058,15 +5045,17 @@ 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
$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_create($tzvalue['tzid']), 'P') . ']';
$timezones[$tzvalue['tzid']] = $tzinfo[0]['abbr'] . ' - ' . $desc . ' [UTC' . date_format($date_when, 'P') . ']';
}

$timezones = array_merge(
Expand All @@ -5078,6 +5067,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
Expand Down

0 comments on commit 9b1f3df

Please sign in to comment.