Passed
Push — master ( 9aa611...cfa144 )
by
unknown
17:17 queued 03:11
created

TimezoneUtil   B

Complexity

Total Complexity 52

Size/Duplication

Total Lines 1484
Duplicated Lines 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
eloc 1003
c 3
b 1
f 0
dl 0
loc 1484
rs 7.028
wmc 52

13 Methods

Rating   Name   Duplication   Size   Complexity  
B getMSTZnameFromTZName() 0 40 10
A guessTZNameFromPHPName() 0 13 4
A FillTZNames() 0 11 2
A GetBinaryTZ() 0 14 3
A GetTZNameFromWinTZ() 0 13 4
C guessTZNameFromOffset() 0 23 13
A GetFullTZFromTZName() 0 30 2
A GetGMTTz() 0 23 1
A GetFullTZ() 0 10 2
A CreateTimezoneDefinitionObject() 0 40 3
A encodeTZName() 0 2 1
A GetTzFromTimezoneDef() 0 40 4
A GetSyncBlobFromTZ() 0 29 3

How to fix   Complexity   

Complex Class

Complex classes like TimezoneUtil often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use TimezoneUtil, and based on these observations, apply Extract Interface, too.

1
<?php
2
/*
3
 * SPDX-License-Identifier: AGPL-3.0-only
4
 * SPDX-FileCopyrightText: Copyright 2007-2016 Zarafa Deutschland GmbH
5
 * SPDX-FileCopyrightText: Copyright 2020-2024 grommunio GmbH
6
 *
7
 * Class to generate AS compatible timezone information
8
 */
9
10
class TimezoneUtil {
11
	/**
12
	 * list of MS and AS compatible timezones.
13
	 *
14
	 * origin: http://msdn.microsoft.com/en-us/library/ms912391%28v=winembedded.11%29.aspx
15
	 * dots of tz identifiers were removed
16
	 *
17
	 * Updated at: 01.06.2012
18
	 */
19
	private static $mstzones = [
20
		"000" => ["Dateline Standard Time", "(GMT-12:00) International Date Line West"],
21
		"001" => ["Samoa Standard Time", "(GMT-11:00) Midway Island, Samoa"],
22
		"002" => ["Hawaiian Standard Time", "(GMT-10:00) Hawaii"],
23
		"003" => ["Alaskan Standard Time", "(GMT-09:00) Alaska"],
24
		"004" => ["Pacific Standard Time", "(GMT-08:00) Pacific Time (US and Canada); Tijuana"],
25
		"010" => ["Mountain Standard Time", "(GMT-07:00) Mountain Time (US and Canada)"],
26
		"013" => ["Mexico Standard Time 2", "(GMT-07:00) Chihuahua, La Paz, Mazatlan"],
27
		"015" => ["US Mountain Standard Time", "(GMT-07:00) Arizona"],
28
		"020" => ["Central Standard Time", "(GMT-06:00) Central Time (US and Canada"],
29
		"025" => ["Canada Central Standard Time", "(GMT-06:00) Saskatchewan"],
30
		"030" => ["Mexico Standard Time", "(GMT-06:00) Guadalajara, Mexico City, Monterrey"],
31
		"033" => ["Central America Standard Time", "(GMT-06:00) Central America"],
32
		"035" => ["Eastern Standard Time", "(GMT-05:00) Eastern Time (US and Canada)"],
33
		"040" => ["US Eastern Standard Time", "(GMT-05:00) Indiana (East)"],
34
		"045" => ["SA Pacific Standard Time", "(GMT-05:00) Bogota, Lima, Quito"],
35
		"uk1" => ["Venezuela Standard Time", "(GMT-04:30) Caracas"],                     // added
36
		"050" => ["Atlantic Standard Time", "(GMT-04:00) Atlantic Time (Canada)"],
37
		"055" => ["SA Western Standard Time", "(GMT-04:00) Caracas, La Paz"],
38
		"056" => ["Pacific SA Standard Time", "(GMT-04:00) Santiago"],
39
		"060" => ["Newfoundland and Labrador Standard Time", "(GMT-03:30) Newfoundland and Labrador"],
40
		"065" => ["E South America Standard Time", "(GMT-03:00) Brasilia"],
41
		"070" => ["SA Eastern Standard Time", "(GMT-03:00) Buenos Aires, Georgetown"],
42
		"073" => ["Greenland Standard Time", "(GMT-03:00) Greenland"],
43
		"075" => ["Mid-Atlantic Standard Time", "(GMT-02:00) Mid-Atlantic"],
44
		"080" => ["Azores Standard Time", "(GMT-01:00) Azores"],
45
		"083" => ["Cape Verde Standard Time", "(GMT-01:00) Cape Verde Islands"],
46
		"085" => ["GMT Standard Time", "(GMT) Greenwich Mean Time: Dublin, Edinburgh, Lisbon, London"],
47
		"090" => ["Greenwich Standard Time", "(GMT) Casablanca, Monrovia"],
48
		"095" => ["Central Europe Standard Time", "(GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague"],
49
		"100" => ["Central European Standard Time", "(GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb"],
50
		"105" => ["Romance Standard Time", "(GMT+01:00) Brussels, Copenhagen, Madrid, Paris"],
51
		"110" => ["W Europe Standard Time", "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"],
52
		"111" => ["W. Europe Standard Time", "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"],
53
		"113" => ["W Central Africa Standard Time", "(GMT+01:00) West Central Africa"],
54
		"115" => ["E Europe Standard Time", "(GMT+02:00) Bucharest"],
55
		"120" => ["Egypt Standard Time", "(GMT+02:00) Cairo"],
56
		"125" => ["FLE Standard Time", "(GMT+02:00) Helsinki, Kiev, Riga, Sofia, Tallinn, Vilnius"],
57
		"130" => ["GTB Standard Time", "(GMT+02:00) Athens, Istanbul, Minsk"],
58
		"135" => ["Israel Standard Time", "(GMT+02:00) Jerusalem"],
59
		"140" => ["South Africa Standard Time", "(GMT+02:00) Harare, Pretoria"],
60
		"145" => ["Russian Standard Time", "(GMT+03:00) Moscow, St. Petersburg, Volgograd"],
61
		"150" => ["Arab Standard Time", "(GMT+03:00) Kuwait, Riyadh"],
62
		"155" => ["E Africa Standard Time", "(GMT+03:00) Nairobi"],
63
		"158" => ["Arabic Standard Time", "(GMT+03:00) Baghdad"],
64
		"160" => ["Iran Standard Time", "(GMT+03:30) Tehran"],
65
		"165" => ["Arabian Standard Time", "(GMT+04:00) Abu Dhabi, Muscat"],
66
		"170" => ["Caucasus Standard Time", "(GMT+04:00) Baku, Tbilisi, Yerevan"],
67
		"175" => ["Transitional Islamic State of Afghanistan Standard Time", "(GMT+04:30) Kabul"],
68
		"180" => ["Ekaterinburg Standard Time", "(GMT+05:00) Ekaterinburg"],
69
		"185" => ["West Asia Standard Time", "(GMT+05:00) Islamabad, Karachi, Tashkent"],
70
		"190" => ["India Standard Time", "(GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi"],
71
		"193" => ["Nepal Standard Time", "(GMT+05:45) Kathmandu"],
72
		"195" => ["Central Asia Standard Time", "(GMT+06:00) Astana, Dhaka"],
73
		"200" => ["Sri Lanka Standard Time", "(GMT+06:00) Sri Jayawardenepura"],
74
		"201" => ["N Central Asia Standard Time", "(GMT+06:00) Almaty, Novosibirsk"],
75
		"203" => ["Myanmar Standard Time", "(GMT+06:30) Yangon Rangoon"],
76
		"205" => ["SE Asia Standard Time", "(GMT+07:00) Bangkok, Hanoi, Jakarta"],
77
		"207" => ["North Asia Standard Time", "(GMT+07:00) Krasnoyarsk"],
78
		"210" => ["China Standard Time", "(GMT+08:00) Beijing, Chongqing, Hong Kong SAR, Urumqi"],
79
		"215" => ["Singapore Standard Time", "(GMT+08:00) Kuala Lumpur, Singapore"],
80
		"220" => ["Taipei Standard Time", "(GMT+08:00) Taipei"],
81
		"225" => ["W Australia Standard Time", "(GMT+08:00) Perth"],
82
		"227" => ["North Asia East Standard Time", "(GMT+08:00) Irkutsk, Ulaanbaatar"],
83
		"230" => ["Korea Standard Time", "(GMT+09:00) Seoul"],
84
		"235" => ["Tokyo Standard Time", "(GMT+09:00) Osaka, Sapporo, Tokyo"],
85
		"240" => ["Yakutsk Standard Time", "(GMT+09:00) Yakutsk"],
86
		"245" => ["AUS Central Standard Time", "(GMT+09:30) Darwin"],
87
		"250" => ["Cen Australia Standard Time", "(GMT+09:30) Adelaide"],
88
		"255" => ["AUS Eastern Standard Time", "(GMT+10:00) Canberra, Melbourne, Sydney"],
89
		"260" => ["E Australia Standard Time", "(GMT+10:00) Brisbane"],
90
		"265" => ["Tasmania Standard Time", "(GMT+10:00) Hobart"],
91
		"270" => ["Vladivostok Standard Time", "(GMT+10:00) Vladivostok"],
92
		"275" => ["West Pacific Standard Time", "(GMT+10:00) Guam, Port Moresby"],
93
		"280" => ["Central Pacific Standard Time", "(GMT+11:00) Magadan, Solomon Islands, New Caledonia"],
94
		"285" => ["Fiji Islands Standard Time", "(GMT+12:00) Fiji Islands, Kamchatka, Marshall Islands"],
95
		"290" => ["New Zealand Standard Time", "(GMT+12:00) Auckland, Wellington"],
96
		"300" => ["Tonga Standard Time", "(GMT+13:00) Nuku'alofa"],
97
	];
98
99
	/**
100
	 * Python generated offset list
101
	 * dots in keys were removed.
102
	 *
103
	 * Array indices
104
	 *  0 = lBias
105
	 *  1 = lStandardBias
106
	 *  2 = lDSTBias
107
	 *  3 = wStartYear
108
	 *  4 = wStartMonth
109
	 *  5 = wStartDOW
110
	 *  6 = wStartDay
111
	 *  7 = wStartHour
112
	 *  8 = wStartMinute
113
	 *  9 = wStartSecond
114
	 * 10 = wStartMilliseconds
115
	 * 11 = wEndYear
116
	 * 12 = wEndMonth
117
	 * 13 = wEndDOW
118
	 * 14 = wEndDay
119
	 * 15 = wEndHour
120
	 * 16 = wEndMinute
121
	 * 17 = wEndSecond
122
	 * 18 = wEndMilloseconds
123
	 *
124
	 * As the $tzoneoffsets and the $mstzones need to be resolved in both directions,
125
	 * some offsets are commented as they are not available in the $mstzones.
126
	 *
127
	 * Created at: 01.06.2012
128
	 */
129
	private static $tzonesoffsets = [
130
		"Transitional Islamic State of Afghanistan Standard Time" => [-270, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
131
		"Alaskan Standard Time" => [540, 0, -60, 0, 11, 0, 1, 2, 0, 0, 0, 0, 3, 0, 2, 2, 0, 0, 0],
132
		"Arab Standard Time" => [-180, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
133
		"Arabian Standard Time" => [-240, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
134
		"Arabic Standard Time" => [-180, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
135
		// "Argentina Standard Time"                   => array(180, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
136
		"Atlantic Standard Time" => [240, 0, -60, 0, 11, 0, 1, 2, 0, 0, 0, 0, 3, 0, 2, 2, 0, 0, 0],
137
		"AUS Central Standard Time" => [-570, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
138
		"AUS Eastern Standard Time" => [-600, 0, -60, 0, 4, 0, 1, 3, 0, 0, 0, 0, 10, 0, 1, 2, 0, 0, 0],
139
		// "Azerbaijan Standard Time"                  => array(-240, 0, -60,  0, 10, 0, 5, 5, 0, 0, 0,  0, 3, 0, 5, 4, 0, 0, 0),
140
		"Azores Standard Time" => [60, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
141
		// "Bangladesh Standard Time"                  => array(-360, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
142
		"Canada Central Standard Time" => [360, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
143
		"Cape Verde Standard Time" => [60, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
144
		"Caucasus Standard Time" => [-240, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
145
		"Cen Australia Standard Time" => [-570, 0, -60, 0, 4, 0, 1, 3, 0, 0, 0, 0, 10, 0, 1, 2, 0, 0, 0],
146
		"Central America Standard Time" => [360, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
147
		"Central Asia Standard Time" => [-360, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
148
		// "Central Brazilian Standard Time"           => array(240, 0, -60,  0, 2, 6, 4, 23, 59, 59, 999,  0, 10, 6, 3, 23, 59, 59, 999),
149
		"Central Europe Standard Time" => [-60, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
150
		"Central European Standard Time" => [-60, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
151
		"Central Pacific Standard Time" => [-660, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
152
		"Central Standard Time" => [360, 0, -60, 0, 11, 0, 1, 2, 0, 0, 0, 0, 3, 0, 2, 2, 0, 0, 0],
153
		"Mexico Standard Time" => [360, 0, -60, 0, 10, 0, 5, 2, 0, 0, 0, 0, 4, 0, 1, 2, 0, 0, 0],
154
		"China Standard Time" => [-480, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
155
		"Dateline Standard Time" => [720, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
156
		"E Africa Standard Time" => [-180, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
157
		"E Australia Standard Time" => [-600, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
158
		"E Europe Standard Time" => [-120, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
159
		"E South America Standard Time" => [180, 0, -60, 0, 2, 6, 4, 23, 59, 59, 999, 0, 10, 6, 3, 23, 59, 59, 999],
160
		"Eastern Standard Time" => [300, 0, -60, 0, 11, 0, 1, 2, 0, 0, 0, 0, 3, 0, 2, 2, 0, 0, 0],
161
		"Egypt Standard Time" => [-120, 0, -60, 0, 9, 4, 5, 23, 59, 59, 999, 0, 4, 4, 5, 23, 59, 59, 999],
162
		"Ekaterinburg Standard Time" => [-300, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
163
		"Fiji Islands Standard Time" => [-720, 0, -60, 0, 3, 0, 5, 3, 0, 0, 0, 0, 10, 0, 4, 2, 0, 0, 0],
164
		"FLE Standard Time" => [-120, 0, -60, 0, 10, 0, 5, 4, 0, 0, 0, 0, 3, 0, 5, 3, 0, 0, 0],
165
		// "Georgian Standard Time"                    => array(-240, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
166
		"GMT Standard Time" => [0, 0, -60, 0, 10, 0, 5, 2, 0, 0, 0, 0, 3, 0, 5, 1, 0, 0, 0],
167
		"Greenland Standard Time" => [180, 0, -60, 0, 10, 6, 5, 23, 0, 0, 0, 0, 3, 6, 4, 22, 0, 0, 0],
168
		"Greenwich Standard Time" => [0, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
169
		"GTB Standard Time" => [-120, 0, -60, 0, 10, 0, 5, 4, 0, 0, 0, 0, 3, 0, 5, 3, 0, 0, 0],
170
		"Hawaiian Standard Time" => [600, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
171
		"India Standard Time" => [-330, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
172
		"Iran Standard Time" => [-210, 0, -60, 0, 9, 1, 3, 23, 59, 59, 999, 0, 3, 6, 3, 23, 59, 59, 999],
173
		"Israel Standard Time" => [-120, 0, -60, 0, 9, 0, 4, 2, 0, 0, 0, 0, 3, 5, 5, 2, 0, 0, 0],
174
		// "Jordan Standard Time"                      => array(-120, 0, -60,  0, 10, 5, 5, 1, 0, 0, 0,  0, 3, 4, 5, 23, 59, 59, 999),
175
		// "Kamchatka Standard Time"                   => array(-720, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0),
176
		"Korea Standard Time" => [-540, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
177
		// "Magadan Standard Time"                     => array(-660, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0),
178
		// "Mauritius Standard Time"                   => array(-240, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
179
		"Mid-Atlantic Standard Time" => [120, 0, -60, 0, 9, 0, 5, 2, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
180
		// "Middle East Standard Time"                 => array(-120, 0, -60,  0, 10, 6, 5, 23, 59, 59, 999,  0, 3, 6, 4, 23, 59, 59, 999),
181
		// "Montevideo Standard Time"                  => array(180, 0, -60,  0, 3, 0, 2, 2, 0, 0, 0,  0, 10, 0, 1, 2, 0, 0, 0),
182
		// "Morocco Standard Time"                     => array(0, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
183
		"Mountain Standard Time" => [420, 0, -60, 0, 11, 0, 1, 2, 0, 0, 0, 0, 3, 0, 2, 2, 0, 0, 0],
184
		"Mexico Standard Time 2" => [420, 0, -60, 0, 10, 0, 5, 2, 0, 0, 0, 0, 4, 0, 1, 2, 0, 0, 0],
185
		"Myanmar Standard Time" => [-390, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
186
		"N Central Asia Standard Time" => [-360, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
187
		// "Namibia Standard Time"                     => array(-60, 0, -60,  0, 4, 0, 1, 2, 0, 0, 0,  0, 9, 0, 1, 2, 0, 0, 0),
188
		"Nepal Standard Time" => [-345, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
189
		"New Zealand Standard Time" => [-720, 0, -60, 0, 4, 0, 1, 3, 0, 0, 0, 0, 9, 0, 5, 2, 0, 0, 0],
190
		"Newfoundland and Labrador Standard Time" => [210, 0, -60, 0, 11, 0, 1, 0, 1, 0, 0, 0, 3, 0, 2, 0, 1, 0, 0],
191
		"North Asia East Standard Time" => [-480, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
192
		"North Asia Standard Time" => [-420, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
193
		"Pacific SA Standard Time" => [240, 0, -60, 0, 3, 6, 2, 23, 59, 59, 999, 0, 10, 6, 2, 23, 59, 59, 999],
194
		"Pacific Standard Time" => [480, 0, -60, 0, 11, 0, 1, 2, 0, 0, 0, 0, 3, 0, 2, 2, 0, 0, 0],
195
		// "Pacific Standard Time (Mexico)"            => array(480, 0, -60,  0, 10, 0, 5, 2, 0, 0, 0,  0, 4, 0, 1, 2, 0, 0, 0),
196
		// "Pakistan Standard Time"                    => array(-300, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
197
		// "Paraguay Standard Time"                    => array(240, 0, -60,  0, 4, 6, 1, 23, 59, 59, 999,  0, 10, 6, 1, 23, 59, 59, 999),
198
		"Romance Standard Time" => [-60, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
199
		"Russian Standard Time" => [-180, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
200
		"SA Eastern Standard Time" => [180, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
201
		"SA Pacific Standard Time" => [300, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
202
		"SA Western Standard Time" => [240, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
203
		"Samoa Standard Time" => [660, 0, -60, 0, 3, 6, 5, 23, 59, 59, 999, 0, 9, 6, 5, 23, 59, 59, 999],
204
		"SE Asia Standard Time" => [-420, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
205
		"Singapore Standard Time" => [-480, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
206
		"South Africa Standard Time" => [-120, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
207
		"Sri Lanka Standard Time" => [-330, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
208
		// "Syria Standard Time"                       => array(-120, 0, -60,  0, 10, 4, 5, 23, 59, 59, 999,  0, 4, 4, 1, 23, 59, 59, 999),
209
		"Taipei Standard Time" => [-480, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
210
		"Tasmania Standard Time" => [-600, 0, -60, 0, 4, 0, 1, 3, 0, 0, 0, 0, 10, 0, 1, 2, 0, 0, 0],
211
		"Tokyo Standard Time" => [-540, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
212
		"Tonga Standard Time" => [-780, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
213
		// "Ulaanbaatar Standard Time"                 => array(-480, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
214
		"US Eastern Standard Time" => [300, 0, -60, 0, 11, 0, 1, 2, 0, 0, 0, 0, 3, 0, 2, 2, 0, 0, 0],
215
		"US Mountain Standard Time" => [420, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
216
		// "UTC"                                       => array(0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
217
		// "UTC+12"                                    => array(-720, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
218
		// "UTC-02"                                    => array(120, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
219
		// "UTC-11"                                    => array(660, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
220
		"Venezuela Standard Time" => [270, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
221
		"Vladivostok Standard Time" => [-600, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
222
		"W Australia Standard Time" => [-480, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
223
		"W Central Africa Standard Time" => [-60, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
224
		"W Europe Standard Time" => [-60, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
225
		"West Asia Standard Time" => [-300, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
226
		"West Pacific Standard Time" => [-600, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
227
		"Yakutsk Standard Time" => [-540, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
228
	];
229
230
	/**
231
	 * Generated list of PHP timezones in GMT timezones.
232
	 *
233
	 * Created at: 01.06.2012
234
	 */
235
	private static $phptimezones = [
236
		// -720 min
237
		"Dateline Standard Time" => [
238
			"Etc/GMT+12",
239
		],
240
241
		// -660 min
242
		"Samoa Standard Time" => [
243
			"Etc/GMT+11",
244
			"Pacific/Midway",
245
			"Pacific/Niue",
246
			"Pacific/Pago_Pago",
247
			"Pacific/Samoa",
248
			"US/Samoa",
249
		],
250
251
		// -600 min
252
		"Hawaiian Standard Time" => [
253
			"America/Adak",
254
			"America/Atka",
255
			"Etc/GMT+10",
256
			"HST",
257
			"Pacific/Honolulu",
258
			"Pacific/Johnston",
259
			"Pacific/Rarotonga",
260
			"Pacific/Tahiti",
261
			"US/Aleutian",
262
			"US/Hawaii",
263
		],
264
265
		// -570 min
266
		"-570" => [
267
			"Pacific/Marquesas",
268
		],
269
270
		// -540 min
271
		"Alaskan Standard Time" => [
272
			"America/Anchorage",
273
			"America/Juneau",
274
			"America/Nome",
275
			"America/Sitka",
276
			"America/Yakutat",
277
			"Etc/GMT+9",
278
			"Pacific/Gambier",
279
			"US/Alaska",
280
		],
281
282
		// -480 min
283
		"Pacific Standard Time" => [
284
			"America/Dawson",
285
			"America/Ensenada",
286
			"America/Los_Angeles",
287
			"America/Metlakatla",
288
			"America/Santa_Isabel",
289
			"America/Tijuana",
290
			"America/Vancouver",
291
			"America/Whitehorse",
292
			"Canada/Pacific",
293
			"Canada/Yukon",
294
			"Etc/GMT+8",
295
			"Mexico/BajaNorte",
296
			"Pacific/Pitcairn",
297
			"PST8PDT",
298
			"US/Pacific",
299
			"US/Pacific-New",
300
		],
301
302
		// -420 min
303
		"US Mountain Standard Time" => [
304
			"America/Boise",
305
			"America/Cambridge_Bay",
306
			"America/Chihuahua",
307
			"America/Creston",
308
			"America/Dawson_Creek",
309
			"America/Denver",
310
			"America/Edmonton",
311
			"America/Hermosillo",
312
			"America/Inuvik",
313
			"America/Mazatlan",
314
			"America/Ojinaga",
315
			"America/Phoenix",
316
			"America/Shiprock",
317
			"America/Yellowknife",
318
			"Canada/Mountain",
319
			"Etc/GMT+7",
320
			"Mexico/BajaSur",
321
			"MST",
322
			"MST7MDT",
323
			"Navajo",
324
			"US/Arizona",
325
			"US/Mountain",
326
		],
327
328
		// -360 min
329
		"Central Standard Time" => [
330
			"America/Chicago",
331
			"America/Indiana/Knox",
332
			"America/Indiana/Tell_City",
333
			"America/Knox_IN",
334
			"America/North_Dakota/Beulah",
335
			"America/North_Dakota/Center",
336
			"America/North_Dakota/New_Salem",
337
			"America/Rainy_River",
338
			"America/Rankin_Inlet",
339
			"America/Regina",
340
			"America/Resolute",
341
			"America/Swift_Current",
342
			"America/Tegucigalpa",
343
			"America/Winnipeg",
344
			"US/Central",
345
			"US/Indiana-Starke",
346
			"CST6CDT",
347
			"Etc/GMT+6",
348
		],
349
		"Canada Central Standard Time" => [
350
			"Canada/Central",
351
			"Canada/East-Saskatchewan",
352
			"Canada/Saskatchewan",
353
		],
354
		"Mexico Standard Time" => [
355
			"America/Mexico_City",
356
			"America/Monterrey",
357
			"Mexico/General",
358
		],
359
		"Central America Standard Time" => [
360
			"America/Bahia_Banderas",
361
			"America/Belize",
362
			"America/Cancun",
363
			"America/Costa_Rica",
364
			"America/El_Salvador",
365
			"America/Guatemala",
366
			"America/Managua",
367
			"America/Matamoros",
368
			"America/Menominee",
369
			"America/Merida",
370
			"Chile/EasterIsland",
371
			"Pacific/Easter",
372
			"Pacific/Galapagos",
373
		],
374
375
		// -300 min
376
		"US Eastern Standard Time" => [
377
			"America/Detroit",
378
			"America/Fort_Wayne",
379
			"America/Grand_Turk",
380
			"America/Indiana/Indianapolis",
381
			"America/Indiana/Marengo",
382
			"America/Indiana/Petersburg",
383
			"America/Indiana/Vevay",
384
			"America/Indiana/Vincennes",
385
			"America/Indiana/Winamac",
386
			"America/Indianapolis",
387
			"America/Jamaica",
388
			"America/Kentucky/Louisville",
389
			"America/Kentucky/Monticello",
390
			"America/Louisville",
391
			"America/Montreal",
392
			"America/New_York",
393
			"America/Thunder_Bay",
394
			"America/Toronto",
395
			"Canada/Eastern",
396
			"Cuba",
397
			"EST",
398
			"EST5EDT",
399
			"Etc/GMT+5",
400
			"Jamaica",
401
			"US/East-Indiana",
402
			"US/Eastern",
403
			"US/Michigan",
404
		],
405
		"SA Pacific Standard Time" => [
406
			"America/Atikokan",
407
			"America/Bogota",
408
			"America/Cayman",
409
			"America/Coral_Harbour",
410
			"America/Guayaquil",
411
			"America/Havana",
412
			"America/Iqaluit",
413
			"America/Lima",
414
			"America/Nassau",
415
			"America/Nipigon",
416
			"America/Panama",
417
			"America/Pangnirtung",
418
			"America/Port-au-Prince",
419
		],
420
421
		// -270 min
422
		"Venezuela Standard Time" => [
423
			"America/Caracas",
424
		],
425
		// -240 min
426
		"Atlantic Standard Time" => [
427
			"America/Barbados",
428
			"America/Blanc-Sablon",
429
			"America/Glace_Bay",
430
			"America/Goose_Bay",
431
			"America/Halifax",
432
			"America/Lower_Princes",
433
			"America/St_Barthelemy",
434
			"America/St_Kitts",
435
			"America/St_Lucia",
436
			"America/St_Thomas",
437
			"America/St_Vincent",
438
			"America/Thule",
439
			"America/Tortola",
440
			"America/Virgin",
441
			"Atlantic/Bermuda",
442
			"Canada/Atlantic",
443
			"Etc/GMT+4",
444
		],
445
		"SA Western Standard Time" => [
446
			"America/Anguilla",
447
			"America/Antigua",
448
			"America/Aruba",
449
			"America/Asuncion",
450
			"America/Boa_Vista",
451
			"America/Campo_Grande",
452
			"America/Cuiaba",
453
			"America/Curacao",
454
			"America/Dominica",
455
			"America/Eirunepe",
456
			"America/Grenada",
457
			"America/Guadeloupe",
458
			"America/Guyana",
459
			"America/Kralendijk",
460
			"America/La_Paz",
461
			"America/Manaus",
462
			"America/Marigot",
463
			"America/Martinique",
464
			"America/Moncton",
465
			"America/Montserrat",
466
			"America/Port_of_Spain",
467
			"America/Porto_Acre",
468
			"America/Porto_Velho",
469
			"America/Puerto_Rico",
470
			"America/Rio_Branco",
471
			"Brazil/Acre",
472
			"Brazil/West",
473
		],
474
		"Pacific SA Standard Time" => [
475
			"America/Santiago",
476
			"America/Santo_Domingo",
477
			"Antarctica/Palmer",
478
			"Chile/Continental",
479
		],
480
481
		// -210 min
482
		"Newfoundland and Labrador Standard Time" => [
483
			"America/St_Johns",
484
			"Canada/Newfoundland",
485
		],
486
487
		// -180 min
488
		"E South America Standard Time" => [
489
			"America/Araguaina",
490
			"America/Bahia",
491
			"America/Belem",
492
			"America/Fortaleza",
493
			"America/Maceio",
494
			"America/Recife",
495
			"America/Sao_Paulo",
496
			"Brazil/East",
497
			"Etc/GMT+3",
498
		],
499
		"SA Eastern Standard Time" => [
500
			"America/Argentina/Buenos_Aires",
501
			"America/Argentina/Catamarca",
502
			"America/Argentina/ComodRivadavia",
503
			"America/Argentina/Cordoba",
504
			"America/Argentina/Jujuy",
505
			"America/Argentina/La_Rioja",
506
			"America/Argentina/Mendoza",
507
			"America/Argentina/Rio_Gallegos",
508
			"America/Argentina/Salta",
509
			"America/Argentina/San_Juan",
510
			"America/Argentina/San_Luis",
511
			"America/Argentina/Tucuman",
512
			"America/Argentina/Ushuaia",
513
			"America/Buenos_Aires",
514
			"America/Catamarca",
515
			"America/Cayenne",
516
			"America/Cordoba",
517
			"America/Godthab",
518
			"America/Jujuy",
519
			"America/Mendoza",
520
			"America/Miquelon",
521
			"America/Montevideo",
522
			"America/Paramaribo",
523
			"America/Rosario",
524
			"America/Santarem",
525
		],
526
		"Greenland Standard Time" => [
527
			"Antarctica/Rothera",
528
			"Atlantic/Stanley",
529
		],
530
531
		// -120 min
532
		"Mid-Atlantic Standard Time" => [
533
			"America/Noronha",
534
			"Atlantic/South_Georgia",
535
			"Brazil/DeNoronha",
536
			"Etc/GMT+2",
537
		],
538
539
		// -60 min
540
		"Azores Standard Time" => [
541
			"Atlantic/Azores",
542
			"Etc/GMT+1",
543
		],
544
		"Cape Verde Standard Time" => [
545
			"America/Scoresbysund",
546
			"Atlantic/Cape_Verde",
547
		],
548
549
		// 0 min
550
		"GMT Standard Time" => [
551
			"Eire",
552
			"Etc/GMT",
553
			"Etc/GMT+0",
554
			"Etc/GMT-0",
555
			"Etc/GMT0",
556
			"Etc/Greenwich",
557
			"Etc/UCT",
558
			"Etc/Universal",
559
			"Etc/UTC",
560
			"Etc/Zulu",
561
			"Europe/Belfast",
562
			"Europe/Dublin",
563
			"Europe/Guernsey",
564
			"Europe/Isle_of_Man",
565
			"Europe/Jersey",
566
			"Europe/Lisbon",
567
			"Europe/London",
568
			"Factory",
569
			"GB",
570
			"GB-Eire",
571
			"GMT",
572
			"GMT+0",
573
			"GMT-0",
574
			"GMT0",
575
			"Greenwich",
576
			"Iceland",
577
			"Portugal",
578
			"UCT",
579
			"Universal",
580
			"UTC",
581
		],
582
		"Greenwich Standard Time" => [
583
			"Africa/Abidjan",
584
			"Africa/Accra",
585
			"Africa/Bamako",
586
			"Africa/Banjul",
587
			"Africa/Bissau",
588
			"Africa/Casablanca",
589
			"Africa/Conakry",
590
			"Africa/Dakar",
591
			"Africa/El_Aaiun",
592
			"Africa/Freetown",
593
			"Africa/Lome",
594
			"Africa/Monrovia",
595
			"Africa/Nouakchott",
596
			"Africa/Ouagadougou",
597
			"Africa/Sao_Tome",
598
			"Africa/Timbuktu",
599
			"America/Danmarkshavn",
600
			"Atlantic/Canary",
601
			"Atlantic/Faeroe",
602
			"Atlantic/Faroe",
603
			"Atlantic/Madeira",
604
			"Atlantic/Reykjavik",
605
			"Atlantic/St_Helena",
606
			"Zulu",
607
		],
608
609
		// +60 min
610
		"Central Europe Standard Time" => [
611
			"Europe/Belgrade",
612
			"Europe/Bratislava",
613
			"Europe/Budapest",
614
			"Europe/Ljubljana",
615
			"Europe/Prague",
616
			"Europe/Vaduz",
617
		],
618
		"Central European Standard Time" => [
619
			"Europe/Sarajevo",
620
			"Europe/Skopje",
621
			"Europe/Warsaw",
622
			"Europe/Zagreb",
623
			"MET",
624
			"Poland",
625
		],
626
		"Romance Standard Time" => [
627
			"Europe/Andorra",
628
			"Europe/Brussels",
629
			"Europe/Copenhagen",
630
			"Europe/Gibraltar",
631
			"Europe/Madrid",
632
			"Europe/Malta",
633
			"Europe/Monaco",
634
			"Europe/Paris",
635
			"Europe/Podgorica",
636
			"Europe/San_Marino",
637
			"Europe/Tirane",
638
		],
639
		"W Europe Standard Time" => [
640
			"Europe/Amsterdam",
641
			"Europe/Berlin",
642
			"Europe/Luxembourg",
643
			"Europe/Vatican",
644
			"Europe/Rome",
645
			"Europe/Stockholm",
646
			"Arctic/Longyearbyen",
647
			"Europe/Vienna",
648
			"Europe/Zurich",
649
			"Europe/Oslo",
650
			"WET",
651
			"CET",
652
			"Etc/GMT-1",
653
		],
654
		"W Central Africa Standard Time" => [
655
			"Africa/Algiers",
656
			"Africa/Bangui",
657
			"Africa/Brazzaville",
658
			"Africa/Ceuta",
659
			"Africa/Douala",
660
			"Africa/Kinshasa",
661
			"Africa/Lagos",
662
			"Africa/Libreville",
663
			"Africa/Luanda",
664
			"Africa/Malabo",
665
			"Africa/Ndjamena",
666
			"Africa/Niamey",
667
			"Africa/Porto-Novo",
668
			"Africa/Tunis",
669
			"Africa/Windhoek",
670
			"Atlantic/Jan_Mayen",
671
		],
672
673
		// +120 min
674
		"E Europe Standard Time" => [
675
			"Europe/Bucharest",
676
			"EET",
677
			"Etc/GMT-2",
678
			"Europe/Chisinau",
679
			"Europe/Mariehamn",
680
			"Europe/Nicosia",
681
			"Europe/Simferopol",
682
			"Europe/Tiraspol",
683
			"Europe/Uzhgorod",
684
			"Europe/Zaporozhye",
685
		],
686
		"Egypt Standard Time" => [
687
			"Africa/Cairo",
688
			"Africa/Tripoli",
689
			"Egypt",
690
			"Libya",
691
		],
692
		"FLE Standard Time" => [
693
			"Europe/Helsinki",
694
			"Europe/Kiev",
695
			"Europe/Riga",
696
			"Europe/Sofia",
697
			"Europe/Tallinn",
698
			"Europe/Vilnius",
699
		],
700
		"GTB Standard Time" => [
701
			"Asia/Istanbul",
702
			"Europe/Athens",
703
			"Europe/Istanbul",
704
			"Turkey",
705
		],
706
		"Israel Standard Time" => [
707
			"Asia/Amman",
708
			"Asia/Beirut",
709
			"Asia/Damascus",
710
			"Asia/Gaza",
711
			"Asia/Hebron",
712
			"Asia/Nicosia",
713
			"Asia/Tel_Aviv",
714
			"Asia/Jerusalem",
715
			"Israel",
716
		],
717
		"South Africa Standard Time" => [
718
			"Africa/Blantyre",
719
			"Africa/Bujumbura",
720
			"Africa/Gaborone",
721
			"Africa/Harare",
722
			"Africa/Johannesburg",
723
			"Africa/Kigali",
724
			"Africa/Lubumbashi",
725
			"Africa/Lusaka",
726
			"Africa/Maputo",
727
			"Africa/Maseru",
728
			"Africa/Mbabane",
729
		],
730
731
		// +180 min
732
		"Russian Standard Time" => [
733
			"Antarctica/Syowa",
734
			"Europe/Kaliningrad",
735
			"Europe/Minsk",
736
			"Etc/GMT-3",
737
		],
738
		"Arab Standard Time" => [
739
			"Asia/Qatar",
740
			"Asia/Kuwait",
741
			"Asia/Riyadh",
742
		],
743
		"E Africa Standard Time" => [
744
			"Africa/Addis_Ababa",
745
			"Africa/Asmara",
746
			"Africa/Asmera",
747
			"Africa/Dar_es_Salaam",
748
			"Africa/Djibouti",
749
			"Africa/Juba",
750
			"Africa/Kampala",
751
			"Africa/Khartoum",
752
			"Africa/Mogadishu",
753
			"Africa/Nairobi",
754
		],
755
		"Arabic Standard Time" => [
756
			"Asia/Aden",
757
			"Asia/Baghdad",
758
			"Asia/Bahrain",
759
			"Indian/Antananarivo",
760
			"Indian/Comoro",
761
			"Indian/Mayotte",
762
		],
763
764
		// +210 min
765
		"Iran Standard Time" => [
766
			"Asia/Tehran",
767
			"Iran",
768
		],
769
770
		// +240 min
771
		"Arabian Standard Time" => [
772
			"Asia/Dubai",
773
			"Asia/Muscat",
774
			"Indian/Mahe",
775
			"Indian/Mauritius",
776
			"Indian/Reunion",
777
		],
778
		"Caucasus Standard Time" => [
779
			"Asia/Baku",
780
			"Asia/Tbilisi",
781
			"Asia/Yerevan",
782
			"Etc/GMT-4",
783
			"Europe/Moscow",
784
			"Europe/Samara",
785
			"Europe/Volgograd",
786
			"W-SU",
787
		],
788
789
		// +270 min
790
		"Transitional Islamic State of Afghanistan Standard Time" => [
791
			"Asia/Kabul",
792
		],
793
794
		// +300 min
795
		"Ekaterinburg Standard Time" => [
796
			"Antarctica/Mawson",
797
		],
798
		"West Asia Standard Time" => [
799
			"Asia/Aqtau",
800
			"Asia/Aqtobe",
801
			"Asia/Ashgabat",
802
			"Asia/Ashkhabad",
803
			"Asia/Dushanbe",
804
			"Asia/Karachi",
805
			"Asia/Oral",
806
			"Asia/Samarkand",
807
			"Asia/Tashkent",
808
			"Etc/GMT-5",
809
			"Indian/Kerguelen",
810
			"Indian/Maldives",
811
		],
812
813
		// +330 min
814
		"India Standard Time" => [
815
			"Asia/Calcutta",
816
			"Asia/Colombo",
817
			"Asia/Kolkata",
818
		],
819
820
		// +345 min
821
		"Nepal Standard Time" => [
822
			"Asia/Kathmandu",
823
			"Asia/Katmandu",
824
		],
825
826
		// +360 min
827
		"Central Asia Standard Time" => [
828
			"Asia/Dacca",
829
			"Asia/Dhaka",
830
		],
831
		"Sri Lanka Standard Time" => [
832
			"Indian/Chagos",
833
		],
834
		"N Central Asia Standard Time" => [
835
			"Antarctica/Vostok",
836
			"Asia/Almaty",
837
			"Asia/Bishkek",
838
			"Asia/Qyzylorda",
839
			"Asia/Thimbu",
840
			"Asia/Thimphu",
841
			"Asia/Yekaterinburg",
842
			"Etc/GMT-6",
843
		],
844
845
		// +390 min
846
		"Myanmar Standard Time" => [
847
			"Asia/Rangoon",
848
			"Indian/Cocos",
849
		],
850
851
		// +420 min
852
		"SE Asia Standard Time" => [
853
			"Asia/Bangkok",
854
			"Asia/Ho_Chi_Minh",
855
			"Asia/Hovd",
856
			"Asia/Jakarta",
857
			"Asia/Phnom_Penh",
858
			"Asia/Saigon",
859
			"Indian/Christmas",
860
		],
861
		"North Asia Standard Time" => [
862
			"Antarctica/Davis",
863
			"Asia/Novokuznetsk",
864
			"Asia/Novosibirsk",
865
			"Asia/Omsk",
866
			"Asia/Pontianak",
867
			"Asia/Vientiane",
868
			"Etc/GMT-7",
869
		],
870
871
		// +480 min
872
		"China Standard Time" => [
873
			"Asia/Brunei",
874
			"Asia/Choibalsan",
875
			"Asia/Chongqing",
876
			"Asia/Chungking",
877
			"Asia/Harbin",
878
			"Asia/Hong_Kong",
879
			"Asia/Shanghai",
880
			"Asia/Ujung_Pandang",
881
			"Asia/Urumqi",
882
			"Hongkong",
883
			"PRC",
884
			"ROC",
885
		],
886
		"Singapore Standard Time" => [
887
			"Singapore",
888
			"Asia/Singapore",
889
			"Asia/Kuala_Lumpur",
890
		],
891
		"Taipei Standard Time" => [
892
			"Asia/Taipei",
893
		],
894
		"W Australia Standard Time" => [
895
			"Australia/Perth",
896
			"Australia/West",
897
		],
898
		"North Asia East Standard Time" => [
899
			"Antarctica/Casey",
900
			"Asia/Kashgar",
901
			"Asia/Krasnoyarsk",
902
			"Asia/Kuching",
903
			"Asia/Macao",
904
			"Asia/Macau",
905
			"Asia/Makassar",
906
			"Asia/Manila",
907
			"Etc/GMT-8",
908
			"Asia/Ulaanbaatar",
909
			"Asia/Ulan_Bator",
910
		],
911
912
		// +525 min
913
		"525" => [
914
			"Australia/Eucla",
915
		],
916
917
		// +540 min
918
		"Korea Standard Time" => [
919
			"Asia/Seoul",
920
			"Asia/Pyongyang",
921
			"ROK",
922
		],
923
		"Tokyo Standard Time" => [
924
			"Asia/Tokyo",
925
			"Japan",
926
			"Etc/GMT-9",
927
		],
928
		"Yakutsk Standard Time" => [
929
			"Asia/Dili",
930
			"Asia/Irkutsk",
931
			"Asia/Jayapura",
932
			"Pacific/Palau",
933
		],
934
935
		// +570 min
936
		"AUS Central Standard Time" => [
937
			"Australia/Darwin",
938
			"Australia/North",
939
		],
940
		// DST
941
		"Cen Australia Standard Time" => [
942
			"Australia/Adelaide",
943
			"Australia/Broken_Hill",
944
			"Australia/South",
945
			"Australia/Yancowinna",
946
		],
947
948
		// +600 min
949
		"AUS Eastern Standard Time" => [
950
			"Australia/Canberra",
951
			"Australia/Melbourne",
952
			"Australia/Sydney",
953
			"Australia/Currie",
954
			"Australia/ACT",
955
			"Australia/NSW",
956
			"Australia/Victoria",
957
		],
958
		"E Australia Standard Time" => [
959
			"Etc/GMT-10",
960
			"Australia/Brisbane",
961
			"Australia/Queensland",
962
			"Australia/Lindeman",
963
		],
964
		"Tasmania Standard Time" => [
965
			"Australia/Hobart",
966
			"Australia/Tasmania",
967
		],
968
		"Vladivostok Standard Time" => [
969
			"Antarctica/DumontDUrville",
970
		],
971
		"West Pacific Standard Time" => [
972
			"Asia/Yakutsk",
973
			"Pacific/Chuuk",
974
			"Pacific/Guam",
975
			"Pacific/Port_Moresby",
976
			"Pacific/Saipan",
977
			"Pacific/Truk",
978
			"Pacific/Yap",
979
		],
980
981
		// +630 min
982
		"630" => [
983
			"Australia/LHI",
984
			"Australia/Lord_Howe",
985
		],
986
987
		// +660 min
988
		"Central Pacific Standard Time" => [
989
			"Antarctica/Macquarie",
990
			"Asia/Sakhalin",
991
			"Asia/Vladivostok",
992
			"Etc/GMT-11",
993
			"Pacific/Efate",
994
			"Pacific/Guadalcanal",
995
			"Pacific/Kosrae",
996
			"Pacific/Noumea",
997
			"Pacific/Pohnpei",
998
			"Pacific/Ponape",
999
		],
1000
1001
		// 690 min
1002
		"690" => [
1003
			"Pacific/Norfolk",
1004
		],
1005
1006
		// +720 min
1007
		"Fiji Islands Standard Time" => [
1008
			"Asia/Anadyr",
1009
			"Asia/Kamchatka",
1010
			"Asia/Magadan",
1011
			"Kwajalein",
1012
		],
1013
		"New Zealand Standard Time" => [
1014
			"Antarctica/McMurdo",
1015
			"Antarctica/South_Pole",
1016
			"Etc/GMT-12",
1017
			"NZ",
1018
			"Pacific/Auckland",
1019
			"Pacific/Fiji",
1020
			"Pacific/Funafuti",
1021
			"Pacific/Kwajalein",
1022
			"Pacific/Majuro",
1023
			"Pacific/Nauru",
1024
			"Pacific/Tarawa",
1025
			"Pacific/Wake",
1026
			"Pacific/Wallis",
1027
		],
1028
1029
		// +765 min
1030
		"765" => [
1031
			"NZ-CHAT",
1032
			"Pacific/Chatham",
1033
		],
1034
1035
		// +780 min
1036
		"Tonga Standard Time" => [
1037
			"Etc/GMT-13",
1038
			"Pacific/Apia",
1039
			"Pacific/Enderbury",
1040
			"Pacific/Tongatapu",
1041
		],
1042
1043
		// +840 min
1044
		"840" => [
1045
			"Etc/GMT-14",
1046
			"Pacific/Fakaofo",
1047
			"Pacific/Kiritimati",
1048
		],
1049
	];
1050
1051
	/**
1052
	 * Returns the binary timezone definition.
1053
	 *
1054
	 * @param string $phptimezone (opt) a php timezone string.
1055
	 *                            If omitted the env. default timezone is used.
1056
	 *
1057
	 * @return array|bool
1058
	 */
1059
	public static function GetBinaryTZ($phptimezone = false) {
1060
		if ($phptimezone === false) {
1061
			$phptimezone = date_default_timezone_get();
1062
		}
1063
		SLog::Write(LOGLEVEL_DEBUG, sprintf("TimezoneUtil::GetBinaryTZ() for %s", $phptimezone));
1064
1065
		try {
1066
			return mapi_ianatz_to_tzdef($phptimezone);
0 ignored issues
show
Bug introduced by
The function mapi_ianatz_to_tzdef was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1066
			return /** @scrutinizer ignore-call */ mapi_ianatz_to_tzdef($phptimezone);
Loading history...
1067
		}
1068
		catch (Exception $e) {
1069
			SLog::Write(LOGLEVEL_WARN, sprintf("TimezoneUtil::GetBinaryTZ() mapi_ianatz_to_tzdef() for '%s' failed!", $phptimezone));
1070
		}
1071
1072
		return false;
1073
	}
1074
1075
	/**
1076
	 * Returns a full timezone array.
1077
	 *
1078
	 * @param string $phptimezone (opt) a php timezone string.
1079
	 *                            If omitted the env. default timezone is used.
1080
	 *
1081
	 * @return array
1082
	 */
1083
	public static function GetFullTZ($phptimezone = false) {
1084
		if ($phptimezone === false) {
1085
			$phptimezone = date_default_timezone_get();
1086
		}
1087
1088
		SLog::Write(LOGLEVEL_DEBUG, "TimezoneUtil::GetFullTZ() for " . $phptimezone);
1089
1090
		$servertzname = self::guessTZNameFromPHPName($phptimezone);
1091
1092
		return self::GetFullTZFromTZName($servertzname);
1093
	}
1094
1095
	/**
1096
	 * Returns a full timezone array.
1097
	 *
1098
	 * @param string $tzname a TZID value
1099
	 *
1100
	 * @return array
1101
	 */
1102
	public static function GetFullTZFromTZName($tzname) {
1103
		if (!array_key_exists($tzname, self::$tzonesoffsets)) {
1104
			SLog::Write(LOGLEVEL_DEBUG, sprintf("TimezoneUtil::GetFullTZFromTZName('%s'): Is a PHP TimeZone, converting", $tzname));
1105
			$tzname = self::guessTZNameFromPHPName($tzname);
1106
		}
1107
1108
		$offset = self::$tzonesoffsets[$tzname];
1109
1110
		return [
1111
			"bias" => $offset[0],
1112
			"tzname" => self::encodeTZName(self::getMSTZnameFromTZName($tzname)),
1113
			"dstendyear" => $offset[3],
1114
			"dstendmonth" => $offset[4],
1115
			"dstendday" => $offset[5],
1116
			"dstendweek" => $offset[6],
1117
			"dstendhour" => $offset[7],
1118
			"dstendminute" => $offset[8],
1119
			"dstendsecond" => $offset[9],
1120
			"dstendmillis" => $offset[10],
1121
			"stdbias" => $offset[1],
1122
			"tznamedst" => self::encodeTZName(self::getMSTZnameFromTZName($tzname)),
1123
			"dststartyear" => $offset[11],
1124
			"dststartmonth" => $offset[12],
1125
			"dststartday" => $offset[13],
1126
			"dststartweek" => $offset[14],
1127
			"dststarthour" => $offset[15],
1128
			"dststartminute" => $offset[16],
1129
			"dststartsecond" => $offset[17],
1130
			"dststartmillis" => $offset[18],
1131
			"dstbias" => $offset[2],
1132
		];
1133
	}
1134
1135
	/**
1136
	 * Sets the timezone name by matching data from the offset (bias etc).
1137
	 *
1138
	 * @param mixed $tz
1139
	 *
1140
	 * @return array
1141
	 */
1142
	public static function FillTZNames($tz) {
1143
		SLog::Write(LOGLEVEL_DEBUG, "TimezoneUtil::FillTZNames() filling up bias " . $tz["bias"]);
1144
		if (!isset($tz["bias"])) {
1145
			SLog::Write(LOGLEVEL_WARN, "TimezoneUtil::FillTZNames() submitted TZ array does not have a bias");
1146
		}
1147
		else {
1148
			$tzname = self::guessTZNameFromOffset($tz);
1149
			$tz['tzname'] = $tz['tznamedst'] = self::encodeTZName(self::getMSTZnameFromTZName($tzname));
1150
		}
1151
1152
		return $tz;
1153
	}
1154
1155
	/**
1156
	 * Tries to find a timezone using the Bias and other offset parameters.
1157
	 *
1158
	 * @param array $offset a grommunio-sync timezone array
1159
	 *
1160
	 * @return string
1161
	 */
1162
	private static function guessTZNameFromOffset($offset) {
1163
		// try to find a quite exact match
1164
		foreach (self::$tzonesoffsets as $tzname => $tzoffset) {
1165
			if ($offset["bias"] == $tzoffset[0] &&
1166
				isset($offset["dstendmonth"]) && $offset["dstendmonth"] == $tzoffset[4] &&
1167
				isset($offset["dstendday"]) && $offset["dstendday"] == $tzoffset[6] &&
1168
				isset($offset["dststartmonth"]) && $offset["dststartmonth"] == $tzoffset[12] &&
1169
				isset($offset["dststartday"]) && $offset["dststartday"] == $tzoffset[14]) {
1170
				return $tzname;
1171
			}
1172
		}
1173
1174
		// try to find a bias match
1175
		foreach (self::$tzonesoffsets as $tzname => $tzoffset) {
1176
			if ($offset["bias"] == $tzoffset[0]) {
1177
				return $tzname;
1178
			}
1179
		}
1180
1181
		// nothing found? return gmt
1182
		SLog::Write(LOGLEVEL_WARN, "TimezoneUtil::guessTZNameFromOffset() no timezone found for the data submitted. Returning 'GMT Standard Time'.");
1183
1184
		return "GMT Standard Time";
1185
	}
1186
1187
	/**
1188
	 * Tries to find a AS timezone for a php timezone.
1189
	 *
1190
	 * @param string $phpname a php timezone name
1191
	 *
1192
	 * @return string
1193
	 */
1194
	private static function guessTZNameFromPHPName($phpname) {
1195
		foreach (self::$phptimezones as $tzn => $phptzs) {
1196
			if (in_array($phpname, $phptzs)) {
1197
				if (!is_int($tzn)) {
1198
					return $tzn;
1199
				}
1200
1201
				break;
1202
			}
1203
		}
1204
		SLog::Write(LOGLEVEL_ERROR, sprintf("TimezoneUtil::guessTZNameFromPHPName() no compatible timezone found for '%s'. Returning 'GMT Standard Time'. Please contact the grommunio dev team.", $phpname));
1205
1206
		return self::$mstzones["085"][0];
1207
	}
1208
1209
	/**
1210
	 * Returns an AS compatible tz name.
1211
	 *
1212
	 * @param string $name internal timezone name
1213
	 *
1214
	 * @return string
1215
	 */
1216
	private static function getMSTZnameFromTZName($name) {
1217
		// if $name is empty, get the timezone from system
1218
		if (trim($name) == '') {
1219
			$name = date_default_timezone_get();
1220
			SLog::Write(LOGLEVEL_INFO, sprintf("TimezoneUtil::getMSTZnameFromTZName(): empty timezone name sent. Got timezone from the system: '%s'", $name));
1221
		}
1222
1223
		foreach (self::$mstzones as $mskey => $msdefs) {
1224
			if ($name == $msdefs[0]) {
1225
				return $msdefs[1];
1226
			}
1227
		}
1228
1229
		// Not found? Then retrieve the correct TZName first and try again.
1230
		// That's ugly and needs a proper fix. But for now this method can convert
1231
		// - Europe/Berlin
1232
		// - W Europe Standard Time
1233
		// to "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"
1234
		// which is more correct than the hardcoded default of (GMT+00:00...)
1235
		$tzName = '';
1236
		foreach (self::$phptimezones as $tzn => $phptzs) {
1237
			if (in_array($name, $phptzs)) {
1238
				$tzName = $tzn;
1239
1240
				break;
1241
			}
1242
		}
1243
		if ($tzName != '') {
1244
			foreach (self::$mstzones as $mskey => $msdefs) {
1245
				if ($tzName == $msdefs[0]) {
1246
					return $msdefs[1];
1247
				}
1248
			}
1249
		}
1250
		if (strpos($name, '.') !== false) {
1251
			return self::getMSTZnameFromTZName(str_replace('.', '', $name));
1252
		}
1253
		SLog::Write(LOGLEVEL_WARN, sprintf("TimezoneUtil::getMSTZnameFromTZName() no MS name found for '%s'. Returning '(GMT) Greenwich Mean Time: Dublin, Edinburgh, Lisbon, London'", $name));
1254
1255
		return self::$mstzones["085"][1];
1256
	}
1257
1258
	/**
1259
	 * Encodes the tz name to UTF-16 compatible with a syncblob.
1260
	 *
1261
	 * @param string $name timezone name
1262
	 *
1263
	 * @return string
1264
	 */
1265
	private static function encodeTZName($name) {
1266
		return substr(iconv('UTF-8', 'UTF-16', $name), 2, -1);
1267
	}
1268
1269
	/**
1270
	 * Pack timezone info for Sync.
1271
	 *
1272
	 * @param array $tz
1273
	 *
1274
	 * @return string
1275
	 */
1276
	public static function GetSyncBlobFromTZ($tz) {
1277
		// set the correct TZ name (done using the Bias)
1278
		if (!isset($tz["tzname"]) || !isset($tz["tznamedst"])) {
1279
			$tz = TimezoneUtil::FillTZNames($tz);
1280
		}
1281
1282
		return pack(
1283
			"la64vvvvvvvvla64vvvvvvvvl",
1284
			$tz["bias"],
1285
			$tz["tzname"],
1286
			0,
1287
			$tz["dstendmonth"],
1288
			$tz["dstendday"],
1289
			$tz["dstendweek"],
1290
			$tz["dstendhour"],
1291
			$tz["dstendminute"],
1292
			$tz["dstendsecond"],
1293
			$tz["dstendmillis"],
1294
			$tz["stdbias"],
1295
			$tz["tznamedst"],
1296
			0,
1297
			$tz["dststartmonth"],
1298
			$tz["dststartday"],
1299
			$tz["dststartweek"],
1300
			$tz["dststarthour"],
1301
			$tz["dststartminute"],
1302
			$tz["dststartsecond"],
1303
			$tz["dststartmillis"],
1304
			$tz["dstbias"]
1305
		);
1306
	}
1307
1308
	/**
1309
	 * Returns official timezone name from windows timezone name.
1310
	 * E.g. "W Europe Standard Time" for "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna".
1311
	 *
1312
	 * @param string $winTz Timezone name in windows
1313
	 *
1314
	 * @return string timezone name
1315
	 */
1316
	public static function GetTZNameFromWinTZ($winTz = false) {
1317
		// Return "GMT Standard Time" per default
1318
		if ($winTz === false) {
1319
			return self::$mstzones['085'][0];
1320
		}
1321
1322
		foreach (self::$mstzones as $mskey => $msdefs) {
1323
			if ($winTz == $msdefs[1]) {
1324
				return $msdefs[0];
1325
			}
1326
		}
1327
1328
		return self::$mstzones['085'][0];
1329
	}
1330
1331
	/**
1332
	 * Returns an GMT timezone array.
1333
	 *
1334
	 * @return array
1335
	 */
1336
	public static function GetGMTTz() {
1337
		return [
1338
			"bias" => 0,
1339
			"tzname" => "",
1340
			"dstendyear" => 0,
1341
			"dstendmonth" => 10,
1342
			"dstendday" => 0,
1343
			"dstendweek" => 5,
1344
			"dstendhour" => 2,
1345
			"dstendminute" => 0,
1346
			"dstendsecond" => 0,
1347
			"dstendmillis" => 0,
1348
			"stdbias" => 0,
1349
			"tznamedst" => "",
1350
			"dststartyear" => 0,
1351
			"dststartmonth" => 3,
1352
			"dststartday" => 0,
1353
			"dststartweek" => 5,
1354
			"dststarthour" => 1,
1355
			"dststartminute" => 0,
1356
			"dststartsecond" => 0,
1357
			"dststartmillis" => 0,
1358
			"dstbias" => -60,
1359
		];
1360
	}
1361
1362
	/**
1363
	 * Creates an array that has split up all the components of a timezone
1364
	 * definition binary.
1365
	 *
1366
	 * Timezone definition structure:
1367
	 *
1368
	 * Major ver : UINT, 1 byte,  2 hex characters
1369
	 * Minor ver : UINT, 1 byte,  2 hex characters
1370
	 * cbHeader  : UINT, 2 bytes, 4 hex characters
1371
	 * Reserved  : UINT, 2 bytes, 4 hex characters
1372
	 * cchKeyName: UINT, 2 bytes, 4 hex characters
1373
	 * KeyName   : CHAR, variable length (defined by cckeyname value)
1374
	 * cRules    : UINT, 2 bytes, 4 hex characters
1375
	 * rules     : STRUCT, variable length (defined by cRules value):
1376
	 *   Major ver     : UINT, 1 byte,  2 hex characters
1377
	 *   Minor ver     : UINT, 1 byte,  2 hex characters
1378
	 *   Reserved      : UINT, 2 bytes, 4 hex characters
1379
	 *   TZRule flags  : UINT, 2 bytes, 4 hex characters
1380
	 *   wYear         : UINT, 2 bytes, 4 hex characters
1381
	 *   X             : TCHAR[14]
1382
	 *   lBias         : LONG, 4 bytes, 8 hex characters
1383
	 *   lStandardBias : LONG, 4 bytes, 8 hex characters
1384
	 *   lDaylightBias : LONG, 4 bytes, 8 hex characters
1385
	 *   stStandardDate: STRUCT
1386
	 *   stDaylightDate: STRUCT
1387
	 *
1388
	 * stStandardDate/stDaylightDate:
1389
	 *   wYear        : UINT, 2 bytes, 4 hex characters
1390
	 *   wMonth       : UINT, 2 bytes, 4 hex characters
1391
	 *   wDayOfWeek   : UINT, 2 bytes, 4 hex characters
1392
	 *   wDay         : UINT, 2 bytes, 4 hex characters
1393
	 *   wHour        : UINT, 2 bytes, 4 hex characters
1394
	 *   wMinute      : UINT, 2 bytes, 4 hex characters
1395
	 *   wSecond      : UINT, 2 bytes, 4 hex characters
1396
	 *   wMilliseconds: UINT, 2 bytes, 4 hex characters
1397
	 *
1398
	 * @param string $tzdef Timezone definition binary
1399
	 *
1400
	 * @return array timezone definition array
1401
	 */
1402
	public static function CreateTimezoneDefinitionObject($tzdef) {
1403
		if (!$tzdef) {
1404
			return [];
1405
		}
1406
1407
		$offset = 0;
1408
1409
		$res = unpack("Cmajorver/Cminorver/vcbheader/vreserved/vcchkeyname", substr($tzdef, $offset, 8));
1410
		$offset += 8;
1411
1412
		$cchKeyName = $res['cchkeyname'] * 2;
1413
		$data = unpack("a{$cchKeyName}keyname/vcrules", substr($tzdef, $offset, $cchKeyName + 2));
1414
		$res['keyname'] = $data['keyname'];
1415
		$res['crules'] = $data['crules'];
1416
		$offset += $cchKeyName + 2;
1417
1418
		for ($i = 0; $i < $res['crules']; ++$i) {
1419
			$rule = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $rule is dead and can be removed.
Loading history...
1420
			$rule = unpack(
1421
				"Cmajorver/Cminorver/vreserved/vtzruleflags/vwyear/a14x/lbias/lstdbias/ldstbias/",
1422
				substr($tzdef, $offset, 34)
1423
			);
1424
			$offset += 34;
1425
1426
			$rule['stStandardDate'] = unpack(
1427
				"vyear/vmonth/vdayofweek/vday/vhour/vminute/vsecond/vmiliseconds/",
1428
				substr($tzdef, $offset, 16)
1429
			);
1430
			$offset += 16;
1431
1432
			$rule['stDaylightDate'] = unpack(
1433
				"vyear/vmonth/vdayofweek/vday/vhour/vminute/vsecond/vmiliseconds/",
1434
				substr($tzdef, $offset, 16)
1435
			);
1436
			$offset += 16;
1437
1438
			$res['rules'][] = $rule;
1439
		}
1440
1441
		return $res;
1442
	}
1443
1444
	/**
1445
	 * Converts timezone definition to timezonetag prop
1446
	 * ("PT_BINARY:PSETID_Appointment:0x8233" aka
1447
	 * "PT_BINARY:PSETID_Appointment:" . PidLidTimeZoneStruct)
1448
	 * compatible structure.
1449
	 *
1450
	 * @param array $tzdef timezone definition array
1451
	 *
1452
	 * @return array
1453
	 */
1454
	public static function GetTzFromTimezoneDef($tzdef) {
1455
		$tz = [
1456
			'tzname' => '',
1457
			'tznamedst' => '',
1458
		];
1459
1460
		foreach ($tzdef['rules'] as $rule) {
1461
			if ($rule['tzruleflags'] & TZRULE_FLAG_EFFECTIVE_TZREG) {
0 ignored issues
show
Bug introduced by
The constant TZRULE_FLAG_EFFECTIVE_TZREG was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1462
				$tz['bias'] = $rule['bias'];
1463
				$tz['dstendyear'] = $rule['stStandardDate']['year'];
1464
				$tz['dstendmonth'] = $rule['stStandardDate']['month'];
1465
				$tz['dstendday'] = $rule['stStandardDate']['day'];
1466
				$tz['dstendweek'] = $rule['stStandardDate']['dayofweek'];
1467
				$tz['dstendhour'] = $rule['stStandardDate']['hour'];
1468
				$tz['dstendminute'] = $rule['stStandardDate']['minute'];
1469
				$tz['dstendsecond'] = $rule['stStandardDate']['second'];
1470
				$tz['dstendmillis'] = $rule['stStandardDate']['miliseconds'];
1471
				$tz['stdbias'] = $rule['stdbias'];
1472
				$tz['dststartyear'] = $rule['stDaylightDate']['year'];
1473
				$tz['dststartmonth'] = $rule['stDaylightDate']['month'];
1474
				$tz['dststartday'] = $rule['stDaylightDate']['day'];
1475
				$tz['dststartweek'] = $rule['stDaylightDate']['dayofweek'];
1476
				$tz['dststarthour'] = $rule['stDaylightDate']['hour'];
1477
				$tz['dststartminute'] = $rule['stDaylightDate']['minute'];
1478
				$tz['dststartsecond'] = $rule['stDaylightDate']['second'];
1479
				$tz['dststartmillis'] = $rule['stDaylightDate']['miliseconds'];
1480
				$tz['dstbias'] = $rule['dstbias'];
1481
			}
1482
		}
1483
1484
		// Fallback if there isn't effective timezone
1485
		if (!isset($tz['bias'])) {
1486
			$tz = self::GetGMTTz();
1487
		}
1488
1489
		// Make the structure compatible with class.recurrence.php
1490
		$tz['timezone'] = $tz['bias'];
1491
		$tz['timezonedst'] = $tz['dstbias'];
1492
1493
		return $tz;
1494
	}
1495
}
1496