jessedp /
php-timezones
| 1 | <?php |
||||
| 2 | |||||
| 3 | namespace jessedp\Timezones; |
||||
| 4 | |||||
| 5 | use DateTime; |
||||
| 6 | use DateTimeZone; |
||||
| 7 | |||||
| 8 | /** |
||||
| 9 | * The Timezones class. |
||||
| 10 | * |
||||
| 11 | * @author jessedp <[email protected]> |
||||
| 12 | */ |
||||
| 13 | class Timezones |
||||
| 14 | { |
||||
| 15 | /** |
||||
| 16 | * Whitespace seperate. |
||||
| 17 | */ |
||||
| 18 | const WHITESPACE_SEP = ' '; |
||||
| 19 | |||||
| 20 | /** |
||||
| 21 | * Popular timezones. |
||||
| 22 | * |
||||
| 23 | * @var array |
||||
| 24 | */ |
||||
| 25 | public static $popularTimezones = [ |
||||
| 26 | 'GMT' => 'GMT timezone', |
||||
| 27 | 'UTC' => 'UTC timezone', |
||||
| 28 | ]; |
||||
| 29 | |||||
| 30 | /** |
||||
| 31 | * The supported regions. |
||||
| 32 | * |
||||
| 33 | * @var array |
||||
| 34 | */ |
||||
| 35 | public static $regions = [ |
||||
| 36 | 'Africa' => DateTimeZone::AFRICA, |
||||
| 37 | 'America' => DateTimeZone::AMERICA, |
||||
| 38 | 'Antarctica' => DateTimeZone::ANTARCTICA, |
||||
| 39 | 'Arctic' => DateTimeZone::ARCTIC, |
||||
| 40 | 'Asia' => DateTimeZone::ASIA, |
||||
| 41 | 'Atlantic' => DateTimeZone::ATLANTIC, |
||||
| 42 | 'Australia' => DateTimeZone::AUSTRALIA, |
||||
| 43 | 'Europe' => DateTimeZone::EUROPE, |
||||
| 44 | 'Indian' => DateTimeZone::INDIAN, |
||||
| 45 | 'Pacific' => DateTimeZone::PACIFIC, |
||||
| 46 | ]; |
||||
| 47 | |||||
| 48 | /** |
||||
| 49 | * Format to display timezones. |
||||
| 50 | * |
||||
| 51 | * @param string $timezone |
||||
| 52 | * @param string $region |
||||
| 53 | * |
||||
| 54 | * @return array |
||||
| 55 | */ |
||||
| 56 | public static function formatTimezone($timezone, $region) |
||||
| 57 | { |
||||
| 58 | $time = new DateTime(null, new DateTimeZone($timezone)); |
||||
| 59 | $str_offset = $time->format('P'); |
||||
| 60 | |||||
| 61 | //clean up the html display |
||||
| 62 | $signs = ['-', '+']; |
||||
| 63 | $signs_r = [' − ', ' + ']; |
||||
| 64 | $offset = str_replace($signs, $signs_r, $str_offset); |
||||
| 65 | |||||
| 66 | //do this for sorting later... |
||||
| 67 | $dbl_offset = (float) str_replace(':', '.', $str_offset); |
||||
| 68 | |||||
| 69 | //only strip things if we're bothering with regions |
||||
| 70 | if (!empty($region)) { |
||||
| 71 | $timezone = substr($timezone, strlen($region) + 1); |
||||
| 72 | } |
||||
| 73 | |||||
| 74 | $timezone = str_replace('St_', 'St. ', $timezone); |
||||
| 75 | $timezone = str_replace('_', ' ', $timezone); |
||||
| 76 | |||||
| 77 | $formatted = '(GMT/UTC'.$offset.')'.self::WHITESPACE_SEP.$timezone; |
||||
| 78 | |||||
| 79 | return ['offset'=>$dbl_offset, 'label' => $formatted]; |
||||
| 80 | } |
||||
| 81 | |||||
| 82 | /** |
||||
| 83 | * Create a timezone HTML select element for form. |
||||
| 84 | * |
||||
| 85 | * @param string $name the name/id to be used for the element |
||||
| 86 | * @param string $selected selected option, defaults to UTC |
||||
| 87 | * @param array $opts various options to set, including: |
||||
| 88 | * @subparam array $attr key=>value pairs of attributes to apply to the select element |
||||
| 89 | * @subparam bool $with_regions whether or not to do region grouping (default=false) |
||||
| 90 | * @subparam array $regions the regions to include, one or more of: Africa, America, Antarctica, |
||||
| 91 | * Arctic, Asia, Atlantic, Australia, Europe, Indian, Pacific |
||||
| 92 | * @return string |
||||
| 93 | **/ |
||||
| 94 | public static function create($name, $selected = 'UTC', $opts = []) |
||||
| 95 | { |
||||
| 96 | //handle a null selected |
||||
| 97 | if (empty($selected)) { |
||||
| 98 | $selected = 'UTC'; |
||||
| 99 | } |
||||
| 100 | |||||
| 101 | // Attributes for select element |
||||
| 102 | $attrSet = ''; |
||||
| 103 | if (isset($opts['attr']) && is_array($opts['attr']) && !empty($opts['attr'])) { |
||||
| 104 | $attr = $opts['attr']; |
||||
| 105 | |||||
| 106 | foreach ($attr as $attr_name => $attr_value) { |
||||
| 107 | $attrSet .= ' '.$attr_name.'="'.$attr_value.'"'; |
||||
| 108 | } |
||||
| 109 | } |
||||
| 110 | |||||
| 111 | //setup grouping |
||||
| 112 | $with_regions = false; |
||||
| 113 | if (isset($opts['with_regions']) && is_bool($opts['with_regions']) && $opts['with_regions']) { |
||||
| 114 | $with_regions = true; |
||||
| 115 | } |
||||
| 116 | |||||
| 117 | $limit_regions = []; |
||||
| 118 | //setup specfic regions - could be better and validate them here too, but, eh... |
||||
| 119 | if (isset($opts['regions']) && is_array($opts['regions']) && !empty($opts['regions'])) { |
||||
| 120 | $limit_regions = $opts['regions']; |
||||
| 121 | } |
||||
| 122 | |||||
| 123 | // start select element |
||||
| 124 | $listbox = '<select name="'.$name.'"'.$attrSet.'>'; |
||||
| 125 | |||||
| 126 | $regions = []; |
||||
| 127 | if ($with_regions) { |
||||
| 128 | $regions = self::$regions; |
||||
| 129 | } elseif (!empty($limit_regions)) { |
||||
| 130 | foreach ($limit_regions as $region) { |
||||
| 131 | $regions[$region] = self::$regions[$region]; |
||||
| 132 | } |
||||
| 133 | } else { |
||||
| 134 | $regions = ['All'=>DateTimeZone::ALL]; |
||||
| 135 | } |
||||
| 136 | // Add all timezones of the regions |
||||
| 137 | // depending on with_regions, this may be one or muiltiple loops |
||||
| 138 | foreach ($regions as $continent => $mask) { |
||||
| 139 | $opts = []; |
||||
| 140 | $timezones = DateTimeZone::listIdentifiers($mask); |
||||
| 141 | |||||
| 142 | if ($with_regions) { |
||||
| 143 | // start optgroup tag |
||||
| 144 | $listbox .= '<optgroup label="'.$continent.'">'; |
||||
| 145 | } else { |
||||
| 146 | //when including everything, don't let formatTimeZone truncate the label. |
||||
| 147 | $continent = null; |
||||
| 148 | } |
||||
| 149 | |||||
| 150 | // create option tags |
||||
| 151 | $offsets = []; |
||||
| 152 | $labels = []; |
||||
| 153 | foreach ($timezones as $timezone) { |
||||
| 154 | $opt = self::formatTimezone($timezone, $continent); |
||||
| 155 | $opt['tz'] = $timezone; |
||||
| 156 | $opt['selected'] = ($selected == $timezone) ? ' selected="selected"' : ''; |
||||
| 157 | $offsets[$timezone] = $opt['offset']; |
||||
| 158 | $labels[$timezone] = $opt['label']; |
||||
| 159 | $opts[] = $opt; |
||||
| 160 | } |
||||
| 161 | |||||
| 162 | array_multisort($offsets, SORT_DESC, |
||||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||
| 163 | $labels, SORT_ASC, $opts |
||||
|
0 ignored issues
–
show
jessedp\Timezones\SORT_ASC cannot be passed to array_multisort() as the parameter $rest expects a reference.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 164 | ); |
||||
| 165 | |||||
| 166 | foreach ($opts as $opt) { |
||||
| 167 | $listbox .= '<option value="'.$opt['tz'].'"'.$opt['selected'].'>'; |
||||
| 168 | $listbox .= $opt['label']; |
||||
| 169 | $listbox .= '</option>'; |
||||
| 170 | } |
||||
| 171 | if ($with_regions) { |
||||
| 172 | // end optgroup tag |
||||
| 173 | $listbox .= '</optgroup>'; |
||||
| 174 | } |
||||
| 175 | } |
||||
| 176 | |||||
| 177 | // end select element |
||||
| 178 | $listbox .= '</select>'; |
||||
| 179 | |||||
| 180 | return $listbox; |
||||
| 181 | } |
||||
| 182 | |||||
| 183 | /** |
||||
| 184 | * Create a timezone array. |
||||
| 185 | * |
||||
| 186 | * @return mixed |
||||
| 187 | **/ |
||||
| 188 | public static function toArray() |
||||
| 189 | { |
||||
| 190 | $list = []; |
||||
| 191 | |||||
| 192 | // Add popular timezones to list |
||||
| 193 | foreach (self::$popularTimezones as $key => $value) { |
||||
| 194 | $list['General'][$key] = $value; |
||||
| 195 | } |
||||
| 196 | |||||
| 197 | // Add all timezone of the regions to return |
||||
| 198 | foreach (self::$regions as $continent => $mask) { |
||||
| 199 | $timezones = DateTimeZone::listIdentifiers($mask); |
||||
| 200 | foreach ($timezones as $timezone) { |
||||
| 201 | $list[$continent][$timezone] = self::formatTimezone($timezone, $continent); |
||||
| 202 | } |
||||
| 203 | } |
||||
| 204 | |||||
| 205 | return $list; |
||||
| 206 | } |
||||
| 207 | |||||
| 208 | /** |
||||
| 209 | * @param int $timestamp |
||||
| 210 | * @param string $timezone |
||||
| 211 | * @param string $format |
||||
| 212 | * |
||||
| 213 | * @return string |
||||
| 214 | */ |
||||
| 215 | public static function convertFromUTC($timestamp, $timezone, $format = 'Y-m-d H:i:s') |
||||
| 216 | { |
||||
| 217 | $date = new DateTime($timestamp, new DateTimeZone('UTC')); |
||||
| 218 | |||||
| 219 | $list = DateTimeZone::listIdentifiers(); |
||||
| 220 | if (!in_array($timezone, $list)) { |
||||
| 221 | $timezone = 'UTC'; |
||||
| 222 | } |
||||
| 223 | $date->setTimezone(new DateTimeZone($timezone)); |
||||
| 224 | |||||
| 225 | return $date->format($format); |
||||
| 226 | } |
||||
| 227 | |||||
| 228 | /** |
||||
| 229 | * Convert a timestamp to UTC. |
||||
| 230 | * @param int $timestamp |
||||
| 231 | * @param string $timezone |
||||
| 232 | * @param string $format |
||||
| 233 | * |
||||
| 234 | * @return string |
||||
| 235 | */ |
||||
| 236 | public static function convertToUTC($timestamp, $timezone, $format = 'Y-m-d H:i:s') |
||||
| 237 | { |
||||
| 238 | $list = DateTimeZone::listIdentifiers(); |
||||
| 239 | if (!in_array($timezone, $list)) { |
||||
| 240 | $timezone = 'UTC'; |
||||
| 241 | } |
||||
| 242 | |||||
| 243 | $date = new DateTime($timestamp, new DateTimeZone($timezone)); |
||||
| 244 | |||||
| 245 | $date->setTimezone(new DateTimeZone('UTC')); |
||||
| 246 | |||||
| 247 | return $date->format($format); |
||||
| 248 | } |
||||
| 249 | } |
||||
| 250 |