Issues (2)

src/Timezones/Timezones.php (2 issues)

Labels
Severity
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 = '&nbsp;&nbsp;&nbsp;&nbsp;';
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 = [' &minus; ', ' &plus; '];
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
jessedp\Timezones\SORT_DESC 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 ignore-type  annotation

162
            array_multisort($offsets, /** @scrutinizer ignore-type */ SORT_DESC,
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 ignore-type  annotation

163
                            $labels, /** @scrutinizer ignore-type */ SORT_ASC, $opts
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