1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 6 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Authors: Derick Rethans <derick@derickrethans.nl> |
16 : +----------------------------------------------------------------------+
17 : */
18 :
19 : /* $Id: php_date.c 290912 2009-11-18 13:24:41Z derick $ */
20 :
21 : #include "php.h"
22 : #include "php_streams.h"
23 : #include "php_main.h"
24 : #include "php_globals.h"
25 : #include "php_ini.h"
26 : #include "ext/standard/info.h"
27 : #include "ext/standard/php_versioning.h"
28 : #include "ext/standard/php_math.h"
29 : #include "php_date.h"
30 : #include "zend_interfaces.h"
31 : #include "lib/timelib.h"
32 : #include <time.h>
33 : #include <unicode/udat.h>
34 :
35 : #ifdef PHP_WIN32
36 : # include "win32/php_stdint.h"
37 : #endif
38 :
39 : #if defined(NETWARE) && defined(__MWERKS__)
40 : static __inline long long llabs( long long i ) { return i >= 0 ? i : -i; }
41 : #endif
42 :
43 : /* {{{ arginfo */
44 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date, 0, 0, 1)
45 : ZEND_ARG_INFO(0, format)
46 : ZEND_ARG_INFO(0, timestamp)
47 : ZEND_END_ARG_INFO()
48 :
49 : ZEND_BEGIN_ARG_INFO_EX(arginfo_gmdate, 0, 0, 1)
50 : ZEND_ARG_INFO(0, format)
51 : ZEND_ARG_INFO(0, timestamp)
52 : ZEND_END_ARG_INFO()
53 :
54 : ZEND_BEGIN_ARG_INFO_EX(arginfo_idate, 0, 0, 1)
55 : ZEND_ARG_INFO(0, format)
56 : ZEND_ARG_INFO(0, timestamp)
57 : ZEND_END_ARG_INFO()
58 :
59 : ZEND_BEGIN_ARG_INFO_EX(arginfo_strtotime, 0, 0, 1)
60 : ZEND_ARG_INFO(0, time)
61 : ZEND_ARG_INFO(0, now)
62 : ZEND_END_ARG_INFO()
63 :
64 : ZEND_BEGIN_ARG_INFO_EX(arginfo_mktime, 0, 0, 0)
65 : ZEND_ARG_INFO(0, hour)
66 : ZEND_ARG_INFO(0, min)
67 : ZEND_ARG_INFO(0, sec)
68 : ZEND_ARG_INFO(0, mon)
69 : ZEND_ARG_INFO(0, day)
70 : ZEND_ARG_INFO(0, year)
71 : ZEND_END_ARG_INFO()
72 :
73 : ZEND_BEGIN_ARG_INFO_EX(arginfo_gmmktime, 0, 0, 0)
74 : ZEND_ARG_INFO(0, hour)
75 : ZEND_ARG_INFO(0, min)
76 : ZEND_ARG_INFO(0, sec)
77 : ZEND_ARG_INFO(0, mon)
78 : ZEND_ARG_INFO(0, day)
79 : ZEND_ARG_INFO(0, year)
80 : ZEND_END_ARG_INFO()
81 :
82 : ZEND_BEGIN_ARG_INFO(arginfo_checkdate, 0)
83 : ZEND_ARG_INFO(0, month)
84 : ZEND_ARG_INFO(0, day)
85 : ZEND_ARG_INFO(0, year)
86 : ZEND_END_ARG_INFO()
87 :
88 : ZEND_BEGIN_ARG_INFO_EX(arginfo_strftime, 0, 0, 1)
89 : ZEND_ARG_INFO(0, format)
90 : ZEND_ARG_INFO(0, timestamp)
91 : ZEND_END_ARG_INFO()
92 :
93 : ZEND_BEGIN_ARG_INFO_EX(arginfo_gmstrftime, 0, 0, 1)
94 : ZEND_ARG_INFO(0, format)
95 : ZEND_ARG_INFO(0, timestamp)
96 : ZEND_END_ARG_INFO()
97 :
98 : ZEND_BEGIN_ARG_INFO(arginfo_time, 0)
99 : ZEND_END_ARG_INFO()
100 :
101 : ZEND_BEGIN_ARG_INFO_EX(arginfo_localtime, 0, 0, 0)
102 : ZEND_ARG_INFO(0, timestamp)
103 : ZEND_ARG_INFO(0, associative_array)
104 : ZEND_END_ARG_INFO()
105 :
106 : ZEND_BEGIN_ARG_INFO_EX(arginfo_getdate, 0, 0, 0)
107 : ZEND_ARG_INFO(0, timestamp)
108 : ZEND_END_ARG_INFO()
109 :
110 : ZEND_BEGIN_ARG_INFO(arginfo_date_default_timezone_set, 0)
111 : ZEND_ARG_INFO(0, timezone_identifier)
112 : ZEND_END_ARG_INFO()
113 :
114 : ZEND_BEGIN_ARG_INFO(arginfo_date_default_timezone_get, 0)
115 : ZEND_END_ARG_INFO()
116 :
117 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_sunrise, 0, 0, 1)
118 : ZEND_ARG_INFO(0, time)
119 : ZEND_ARG_INFO(0, format)
120 : ZEND_ARG_INFO(0, latitude)
121 : ZEND_ARG_INFO(0, longitude)
122 : ZEND_ARG_INFO(0, zenith)
123 : ZEND_ARG_INFO(0, gmt_offset)
124 : ZEND_END_ARG_INFO()
125 :
126 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_sunset, 0, 0, 1)
127 : ZEND_ARG_INFO(0, time)
128 : ZEND_ARG_INFO(0, format)
129 : ZEND_ARG_INFO(0, latitude)
130 : ZEND_ARG_INFO(0, longitude)
131 : ZEND_ARG_INFO(0, zenith)
132 : ZEND_ARG_INFO(0, gmt_offset)
133 : ZEND_END_ARG_INFO()
134 :
135 : ZEND_BEGIN_ARG_INFO(arginfo_date_sun_info, 0)
136 : ZEND_ARG_INFO(0, time)
137 : ZEND_ARG_INFO(0, latitude)
138 : ZEND_ARG_INFO(0, longitude)
139 : ZEND_END_ARG_INFO()
140 :
141 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_create, 0, 0, 0)
142 : ZEND_ARG_INFO(0, time)
143 : ZEND_ARG_INFO(0, object)
144 : ZEND_END_ARG_INFO()
145 :
146 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_create_from_format, 0, 0, 2)
147 : ZEND_ARG_INFO(0, format)
148 : ZEND_ARG_INFO(0, time)
149 : ZEND_ARG_INFO(0, object)
150 : ZEND_END_ARG_INFO()
151 :
152 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_parse, 0, 0, 1)
153 : ZEND_ARG_INFO(0, date)
154 : ZEND_END_ARG_INFO()
155 :
156 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_parse_from_format, 0, 0, 2)
157 : ZEND_ARG_INFO(0, format)
158 : ZEND_ARG_INFO(0, date)
159 : ZEND_END_ARG_INFO()
160 :
161 : ZEND_BEGIN_ARG_INFO(arginfo_date_get_last_errors, 0)
162 : ZEND_END_ARG_INFO()
163 :
164 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_format, 0, 0, 2)
165 : ZEND_ARG_INFO(0, object)
166 : ZEND_ARG_INFO(0, format)
167 : ZEND_END_ARG_INFO()
168 :
169 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_format, 0, 0, 1)
170 : ZEND_ARG_INFO(0, format)
171 : ZEND_END_ARG_INFO()
172 :
173 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_modify, 0, 0, 2)
174 : ZEND_ARG_INFO(0, object)
175 : ZEND_ARG_INFO(0, modify)
176 : ZEND_END_ARG_INFO()
177 :
178 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_modify, 0, 0, 1)
179 : ZEND_ARG_INFO(0, modify)
180 : ZEND_END_ARG_INFO()
181 :
182 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_add, 0, 0, 2)
183 : ZEND_ARG_INFO(0, object)
184 : ZEND_ARG_INFO(0, interval)
185 : ZEND_END_ARG_INFO()
186 :
187 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_add, 0, 0, 1)
188 : ZEND_ARG_INFO(0, interval)
189 : ZEND_END_ARG_INFO()
190 :
191 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_sub, 0, 0, 2)
192 : ZEND_ARG_INFO(0, object)
193 : ZEND_ARG_INFO(0, interval)
194 : ZEND_END_ARG_INFO()
195 :
196 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_sub, 0, 0, 1)
197 : ZEND_ARG_INFO(0, interval)
198 : ZEND_END_ARG_INFO()
199 :
200 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timezone_get, 0, 0, 1)
201 : ZEND_ARG_INFO(0, object)
202 : ZEND_END_ARG_INFO()
203 :
204 : ZEND_BEGIN_ARG_INFO(arginfo_date_method_timezone_get, 0)
205 : ZEND_END_ARG_INFO()
206 :
207 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timezone_set, 0, 0, 2)
208 : ZEND_ARG_INFO(0, object)
209 : ZEND_ARG_INFO(0, timezone)
210 : ZEND_END_ARG_INFO()
211 :
212 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_timezone_set, 0, 0, 1)
213 : ZEND_ARG_INFO(0, timezone)
214 : ZEND_END_ARG_INFO()
215 :
216 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_offset_get, 0, 0, 1)
217 : ZEND_ARG_INFO(0, object)
218 : ZEND_END_ARG_INFO()
219 :
220 : ZEND_BEGIN_ARG_INFO(arginfo_date_method_offset_get, 0)
221 : ZEND_END_ARG_INFO()
222 :
223 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_diff, 0, 0, 2)
224 : ZEND_ARG_INFO(0, object)
225 : ZEND_ARG_INFO(0, object2)
226 : ZEND_ARG_INFO(0, absolute)
227 : ZEND_END_ARG_INFO()
228 :
229 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_diff, 0, 0, 1)
230 : ZEND_ARG_INFO(0, object)
231 : ZEND_ARG_INFO(0, absolute)
232 : ZEND_END_ARG_INFO()
233 :
234 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_time_set, 0, 0, 3)
235 : ZEND_ARG_INFO(0, object)
236 : ZEND_ARG_INFO(0, hour)
237 : ZEND_ARG_INFO(0, minute)
238 : ZEND_ARG_INFO(0, second)
239 : ZEND_END_ARG_INFO()
240 :
241 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_time_set, 0, 0, 2)
242 : ZEND_ARG_INFO(0, hour)
243 : ZEND_ARG_INFO(0, minute)
244 : ZEND_ARG_INFO(0, second)
245 : ZEND_END_ARG_INFO()
246 :
247 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_date_set, 0, 0, 4)
248 : ZEND_ARG_INFO(0, object)
249 : ZEND_ARG_INFO(0, year)
250 : ZEND_ARG_INFO(0, month)
251 : ZEND_ARG_INFO(0, day)
252 : ZEND_END_ARG_INFO()
253 :
254 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_date_set, 0, 0, 3)
255 : ZEND_ARG_INFO(0, year)
256 : ZEND_ARG_INFO(0, month)
257 : ZEND_ARG_INFO(0, day)
258 : ZEND_END_ARG_INFO()
259 :
260 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_isodate_set, 0, 0, 3)
261 : ZEND_ARG_INFO(0, object)
262 : ZEND_ARG_INFO(0, year)
263 : ZEND_ARG_INFO(0, week)
264 : ZEND_ARG_INFO(0, day)
265 : ZEND_END_ARG_INFO()
266 :
267 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_isodate_set, 0, 0, 2)
268 : ZEND_ARG_INFO(0, year)
269 : ZEND_ARG_INFO(0, week)
270 : ZEND_ARG_INFO(0, day)
271 : ZEND_END_ARG_INFO()
272 :
273 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timestamp_set, 0, 0, 2)
274 : ZEND_ARG_INFO(0, object)
275 : ZEND_ARG_INFO(0, unixtimestamp)
276 : ZEND_END_ARG_INFO()
277 :
278 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_timestamp_set, 0, 0, 1)
279 : ZEND_ARG_INFO(0, unixtimestamp)
280 : ZEND_END_ARG_INFO()
281 :
282 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timestamp_get, 0, 0, 1)
283 : ZEND_ARG_INFO(0, object)
284 : ZEND_END_ARG_INFO()
285 :
286 : ZEND_BEGIN_ARG_INFO(arginfo_date_method_timestamp_get, 0)
287 : ZEND_END_ARG_INFO()
288 :
289 : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_open, 0, 0, 1)
290 : ZEND_ARG_INFO(0, timezone)
291 : ZEND_END_ARG_INFO()
292 :
293 : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_name_get, 0, 0, 1)
294 : ZEND_ARG_INFO(0, object)
295 : ZEND_END_ARG_INFO()
296 :
297 : ZEND_BEGIN_ARG_INFO(arginfo_timezone_method_name_get, 0)
298 : ZEND_END_ARG_INFO()
299 :
300 : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_name_from_abbr, 0, 0, 1)
301 : ZEND_ARG_INFO(0, abbr)
302 : ZEND_ARG_INFO(0, gmtoffset)
303 : ZEND_ARG_INFO(0, isdst)
304 : ZEND_END_ARG_INFO()
305 :
306 : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_offset_get, 0, 0, 2)
307 : ZEND_ARG_INFO(0, object)
308 : ZEND_ARG_INFO(0, datetime)
309 : ZEND_END_ARG_INFO()
310 :
311 : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_method_offset_get, 0, 0, 1)
312 : ZEND_ARG_INFO(0, datetime)
313 : ZEND_END_ARG_INFO()
314 :
315 : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_transitions_get, 0, 0, 1)
316 : ZEND_ARG_INFO(0, object)
317 : ZEND_ARG_INFO(0, timestamp_begin)
318 : ZEND_ARG_INFO(0, timestamp_end)
319 : ZEND_END_ARG_INFO()
320 :
321 : ZEND_BEGIN_ARG_INFO(arginfo_timezone_method_transitions_get, 0)
322 : ZEND_ARG_INFO(0, timestamp_begin)
323 : ZEND_ARG_INFO(0, timestamp_end)
324 : ZEND_END_ARG_INFO()
325 :
326 : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_location_get, 0, 0, 1)
327 : ZEND_ARG_INFO(0, object)
328 : ZEND_END_ARG_INFO()
329 :
330 : ZEND_BEGIN_ARG_INFO(arginfo_timezone_method_location_get, 0)
331 : ZEND_END_ARG_INFO()
332 :
333 : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_identifiers_list, 0, 0, 0)
334 : ZEND_ARG_INFO(0, what)
335 : ZEND_ARG_INFO(0, country)
336 : ZEND_END_ARG_INFO()
337 :
338 : ZEND_BEGIN_ARG_INFO(arginfo_timezone_abbreviations_list, 0)
339 : ZEND_END_ARG_INFO()
340 :
341 : ZEND_BEGIN_ARG_INFO(arginfo_timezone_version_get, 0)
342 : ZEND_END_ARG_INFO()
343 :
344 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_create_from_date_string, 0, 0, 1)
345 : ZEND_ARG_INFO(0, time)
346 : ZEND_END_ARG_INFO()
347 :
348 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_format, 0, 0, 2)
349 : ZEND_ARG_INFO(0, object)
350 : ZEND_ARG_INFO(0, format)
351 : ZEND_END_ARG_INFO()
352 :
353 : ZEND_BEGIN_ARG_INFO(arginfo_date_method_interval_format, 0)
354 : ZEND_ARG_INFO(0, format)
355 : ZEND_END_ARG_INFO()
356 :
357 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_period_construct, 0, 0, 3)
358 : ZEND_ARG_INFO(0, start)
359 : ZEND_ARG_INFO(0, interval)
360 : ZEND_ARG_INFO(0, end)
361 : ZEND_END_ARG_INFO()
362 :
363 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_construct, 0, 0, 0)
364 : ZEND_ARG_INFO(0, interval_spec)
365 : ZEND_END_ARG_INFO()
366 :
367 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_format_locale, 0, 0, 2)
368 : ZEND_ARG_INFO(0, object)
369 : ZEND_ARG_INFO(0, format)
370 : ZEND_END_ARG_INFO()
371 : /* }}} */
372 :
373 : /* {{{ Function table */
374 : const zend_function_entry date_functions[] = {
375 : PHP_FE(strtotime, arginfo_strtotime)
376 : PHP_FE(date, arginfo_date)
377 : PHP_FE(idate, arginfo_idate)
378 : PHP_FE(gmdate, arginfo_gmdate)
379 : PHP_FE(mktime, arginfo_mktime)
380 : PHP_FE(gmmktime, arginfo_gmmktime)
381 : PHP_FE(checkdate, arginfo_checkdate)
382 :
383 : #ifdef HAVE_STRFTIME
384 : PHP_FE(strftime, arginfo_strftime)
385 : PHP_FE(gmstrftime, arginfo_gmstrftime)
386 : #endif
387 :
388 : PHP_FE(time, arginfo_time)
389 : PHP_FE(localtime, arginfo_localtime)
390 : PHP_FE(getdate, arginfo_getdate)
391 :
392 : /* Advanced Interface */
393 : PHP_FE(date_create, arginfo_date_create)
394 : PHP_FE(date_create_from_format, arginfo_date_create_from_format)
395 : PHP_FE(date_parse, arginfo_date_parse)
396 : PHP_FE(date_parse_from_format, arginfo_date_parse_from_format)
397 : PHP_FE(date_get_last_errors, arginfo_date_get_last_errors)
398 : PHP_FE(date_format, arginfo_date_format)
399 : PHP_FE(date_format_locale, arginfo_date_format_locale)
400 : PHP_FE(date_modify, arginfo_date_modify)
401 : PHP_FE(date_add, arginfo_date_add)
402 : PHP_FE(date_sub, arginfo_date_sub)
403 : PHP_FE(date_timezone_get, arginfo_date_timezone_get)
404 : PHP_FE(date_timezone_set, arginfo_date_timezone_set)
405 : PHP_FE(date_offset_get, arginfo_date_offset_get)
406 : PHP_FE(date_diff, arginfo_date_diff)
407 :
408 : PHP_FE(date_time_set, arginfo_date_time_set)
409 : PHP_FE(date_date_set, arginfo_date_date_set)
410 : PHP_FE(date_isodate_set, arginfo_date_isodate_set)
411 : PHP_FE(date_timestamp_set, arginfo_date_timestamp_set)
412 : PHP_FE(date_timestamp_get, arginfo_date_timestamp_get)
413 :
414 : PHP_FE(timezone_open, arginfo_timezone_open)
415 : PHP_FE(timezone_name_get, arginfo_timezone_name_get)
416 : PHP_FE(timezone_name_from_abbr, arginfo_timezone_name_from_abbr)
417 : PHP_FE(timezone_offset_get, arginfo_timezone_offset_get)
418 : PHP_FE(timezone_transitions_get, arginfo_timezone_transitions_get)
419 : PHP_FE(timezone_location_get, arginfo_timezone_location_get)
420 : PHP_FE(timezone_identifiers_list, arginfo_timezone_identifiers_list)
421 : PHP_FE(timezone_abbreviations_list, arginfo_timezone_abbreviations_list)
422 : PHP_FE(timezone_version_get, arginfo_timezone_version_get)
423 :
424 : PHP_FE(date_interval_create_from_date_string, arginfo_date_interval_create_from_date_string)
425 : PHP_FE(date_interval_format, arginfo_date_interval_format)
426 :
427 : /* Options and Configuration */
428 : PHP_FE(date_default_timezone_set, arginfo_date_default_timezone_set)
429 : PHP_FE(date_default_timezone_get, arginfo_date_default_timezone_get)
430 :
431 : /* Astronomical functions */
432 : PHP_FE(date_sunrise, arginfo_date_sunrise)
433 : PHP_FE(date_sunset, arginfo_date_sunset)
434 : PHP_FE(date_sun_info, arginfo_date_sun_info)
435 : {NULL, NULL, NULL}
436 : };
437 :
438 : const zend_function_entry date_funcs_date[] = {
439 : PHP_ME(DateTime, __construct, arginfo_date_create, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
440 : PHP_ME(DateTime, __wakeup, NULL, ZEND_ACC_PUBLIC)
441 : PHP_ME(DateTime, __set_state, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
442 : PHP_ME_MAPPING(createFromFormat, date_create_from_format, arginfo_date_create_from_format, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
443 : PHP_ME_MAPPING(getLastErrors, date_get_last_errors, arginfo_date_get_last_errors, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
444 : PHP_ME_MAPPING(format, date_format, arginfo_date_method_format, 0)
445 : PHP_ME_MAPPING(modify, date_modify, arginfo_date_method_modify, 0)
446 : PHP_ME_MAPPING(add, date_add, arginfo_date_method_add, 0)
447 : PHP_ME_MAPPING(sub, date_sub, arginfo_date_method_sub, 0)
448 : PHP_ME_MAPPING(getTimezone, date_timezone_get, arginfo_date_method_timezone_get, 0)
449 : PHP_ME_MAPPING(setTimezone, date_timezone_set, arginfo_date_method_timezone_set, 0)
450 : PHP_ME_MAPPING(getOffset, date_offset_get, arginfo_date_method_offset_get, 0)
451 : PHP_ME_MAPPING(setTime, date_time_set, arginfo_date_method_time_set, 0)
452 : PHP_ME_MAPPING(setDate, date_date_set, arginfo_date_method_date_set, 0)
453 : PHP_ME_MAPPING(setISODate, date_isodate_set, arginfo_date_method_isodate_set, 0)
454 : PHP_ME_MAPPING(setTimestamp, date_timestamp_set, arginfo_date_method_timestamp_set, 0)
455 : PHP_ME_MAPPING(getTimestamp, date_timestamp_get, arginfo_date_method_timestamp_get, 0)
456 : PHP_ME_MAPPING(diff, date_diff, arginfo_date_method_diff, 0)
457 : {NULL, NULL, NULL}
458 : };
459 :
460 : const zend_function_entry date_funcs_timezone[] = {
461 : PHP_ME(DateTimeZone, __construct, arginfo_timezone_open, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
462 : PHP_ME_MAPPING(getName, timezone_name_get, arginfo_timezone_method_name_get, 0)
463 : PHP_ME_MAPPING(getOffset, timezone_offset_get, arginfo_timezone_method_offset_get, 0)
464 : PHP_ME_MAPPING(getTransitions, timezone_transitions_get, arginfo_timezone_method_transitions_get, 0)
465 : PHP_ME_MAPPING(getLocation, timezone_location_get, arginfo_timezone_method_location_get, 0)
466 : PHP_ME_MAPPING(listAbbreviations, timezone_abbreviations_list, arginfo_timezone_abbreviations_list, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
467 : PHP_ME_MAPPING(listIdentifiers, timezone_identifiers_list, arginfo_timezone_identifiers_list, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
468 : {NULL, NULL, NULL}
469 : };
470 :
471 : const zend_function_entry date_funcs_interval[] = {
472 : PHP_ME(DateInterval, __construct, arginfo_date_interval_construct, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
473 : PHP_ME_MAPPING(format, date_interval_format, arginfo_date_method_interval_format, 0)
474 : PHP_ME_MAPPING(createFromDateString, date_interval_create_from_date_string, arginfo_date_interval_create_from_date_string, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
475 : {NULL, NULL, NULL}
476 : };
477 :
478 : const zend_function_entry date_funcs_period[] = {
479 : PHP_ME(DatePeriod, __construct, arginfo_date_period_construct, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
480 : {NULL, NULL, NULL}
481 : };
482 :
483 : static char* guess_timezone(const timelib_tzdb *tzdb TSRMLS_DC);
484 : static void date_register_classes(TSRMLS_D);
485 : static zval * date_instantiate(zend_class_entry *pce, zval *object TSRMLS_DC);
486 : /* }}} */
487 :
488 : ZEND_DECLARE_MODULE_GLOBALS(date)
489 : static PHP_GINIT_FUNCTION(date);
490 :
491 : /* True global */
492 : timelib_tzdb *php_date_global_timezone_db;
493 : int php_date_global_timezone_db_enabled;
494 :
495 : #define DATE_DEFAULT_LATITUDE "31.7667"
496 : #define DATE_DEFAULT_LONGITUDE "35.2333"
497 :
498 : /* on 90'35; common sunset declaration (start of sun body appear) */
499 : #define DATE_SUNSET_ZENITH "90.583333"
500 :
501 : /* on 90'35; common sunrise declaration (sun body disappeared) */
502 : #define DATE_SUNRISE_ZENITH "90.583333"
503 :
504 : /* {{{ INI Settings */
505 : PHP_INI_BEGIN()
506 : STD_PHP_INI_ENTRY("date.timezone", "", PHP_INI_ALL, OnUpdateString, default_timezone, zend_date_globals, date_globals)
507 : PHP_INI_ENTRY("date.default_latitude", DATE_DEFAULT_LATITUDE, PHP_INI_ALL, NULL)
508 : PHP_INI_ENTRY("date.default_longitude", DATE_DEFAULT_LONGITUDE, PHP_INI_ALL, NULL)
509 : PHP_INI_ENTRY("date.sunset_zenith", DATE_SUNSET_ZENITH, PHP_INI_ALL, NULL)
510 : PHP_INI_ENTRY("date.sunrise_zenith", DATE_SUNRISE_ZENITH, PHP_INI_ALL, NULL)
511 : PHP_INI_END()
512 : /* }}} */
513 :
514 : zend_class_entry *date_ce_date, *date_ce_timezone, *date_ce_interval, *date_ce_period;
515 :
516 :
517 : PHPAPI zend_class_entry *php_date_get_date_ce(void)
518 0 : {
519 0 : return date_ce_date;
520 : }
521 :
522 : PHPAPI zend_class_entry *php_date_get_timezone_ce(void)
523 0 : {
524 0 : return date_ce_timezone;
525 : }
526 :
527 : static zend_object_handlers date_object_handlers_date;
528 : static zend_object_handlers date_object_handlers_timezone;
529 : static zend_object_handlers date_object_handlers_interval;
530 : static zend_object_handlers date_object_handlers_period;
531 :
532 : #define DATE_SET_CONTEXT \
533 : zval *object; \
534 : object = getThis(); \
535 :
536 : #define DATE_FETCH_OBJECT \
537 : php_date_obj *obj; \
538 : DATE_SET_CONTEXT; \
539 : if (object) { \
540 : if (zend_parse_parameters_none() == FAILURE) { \
541 : return; \
542 : } \
543 : } else { \
544 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, NULL, "O", &object, date_ce_date) == FAILURE) { \
545 : RETURN_FALSE; \
546 : } \
547 : } \
548 : obj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); \
549 :
550 : #define DATE_CHECK_INITIALIZED(member, class_name) \
551 : if (!(member)) { \
552 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "The " #class_name " object has not been correctly initialized by its constructor"); \
553 : RETURN_FALSE; \
554 : }
555 :
556 : static void date_object_free_storage_date(void *object TSRMLS_DC);
557 : static void date_object_free_storage_timezone(void *object TSRMLS_DC);
558 : static void date_object_free_storage_interval(void *object TSRMLS_DC);
559 : static void date_object_free_storage_period(void *object TSRMLS_DC);
560 :
561 : static zend_object_value date_object_new_date(zend_class_entry *class_type TSRMLS_DC);
562 : static zend_object_value date_object_new_timezone(zend_class_entry *class_type TSRMLS_DC);
563 : static zend_object_value date_object_new_interval(zend_class_entry *class_type TSRMLS_DC);
564 : static zend_object_value date_object_new_period(zend_class_entry *class_type TSRMLS_DC);
565 :
566 : static zend_object_value date_object_clone_date(zval *this_ptr TSRMLS_DC);
567 : static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC);
568 : static zend_object_value date_object_clone_interval(zval *this_ptr TSRMLS_DC);
569 : static zend_object_value date_object_clone_period(zval *this_ptr TSRMLS_DC);
570 :
571 : static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC);
572 : static HashTable *date_object_get_properties(zval *object TSRMLS_DC);
573 : static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC);
574 :
575 : zval *date_interval_read_property(zval *object, zval *member, int type TSRMLS_DC);
576 : void date_interval_write_property(zval *object, zval *member, zval *value TSRMLS_DC);
577 :
578 : /* {{{ Module struct */
579 : zend_module_entry date_module_entry = {
580 : STANDARD_MODULE_HEADER_EX,
581 : NULL,
582 : NULL,
583 : "date", /* extension name */
584 : date_functions, /* function list */
585 : PHP_MINIT(date), /* process startup */
586 : PHP_MSHUTDOWN(date), /* process shutdown */
587 : PHP_RINIT(date), /* request startup */
588 : PHP_RSHUTDOWN(date), /* request shutdown */
589 : PHP_MINFO(date), /* extension info */
590 : PHP_VERSION, /* extension version */
591 : PHP_MODULE_GLOBALS(date), /* globals descriptor */
592 : PHP_GINIT(date), /* globals ctor */
593 : NULL, /* globals dtor */
594 : NULL, /* post deactivate */
595 : STANDARD_MODULE_PROPERTIES_EX
596 : };
597 : /* }}} */
598 :
599 :
600 : /* {{{ PHP_GINIT_FUNCTION */
601 : static PHP_GINIT_FUNCTION(date)
602 17007 : {
603 17007 : date_globals->default_timezone = NULL;
604 17007 : date_globals->timezone = NULL;
605 17007 : date_globals->tzcache = NULL;
606 17007 : }
607 : /* }}} */
608 :
609 :
610 : static void _php_date_tzinfo_dtor(void *tzinfo)
611 588 : {
612 588 : timelib_tzinfo **tzi = (timelib_tzinfo **)tzinfo;
613 :
614 588 : timelib_tzinfo_dtor(*tzi);
615 588 : }
616 :
617 : /* {{{ PHP_RINIT_FUNCTION */
618 : PHP_RINIT_FUNCTION(date)
619 16993 : {
620 16993 : if (DATEG(timezone)) {
621 0 : efree(DATEG(timezone));
622 : }
623 16993 : DATEG(timezone) = NULL;
624 16993 : DATEG(tzcache) = NULL;
625 16993 : DATEG(last_errors) = NULL;
626 :
627 16993 : return SUCCESS;
628 : }
629 : /* }}} */
630 :
631 : /* {{{ PHP_RSHUTDOWN_FUNCTION */
632 : PHP_RSHUTDOWN_FUNCTION(date)
633 17025 : {
634 17025 : if (DATEG(timezone)) {
635 425 : efree(DATEG(timezone));
636 : }
637 17025 : DATEG(timezone) = NULL;
638 17025 : if(DATEG(tzcache)) {
639 445 : zend_hash_destroy(DATEG(tzcache));
640 445 : FREE_HASHTABLE(DATEG(tzcache));
641 445 : DATEG(tzcache) = NULL;
642 : }
643 17025 : if (DATEG(last_errors)) {
644 116 : timelib_error_container_dtor(DATEG(last_errors));
645 116 : DATEG(last_errors) = NULL;
646 : }
647 :
648 17025 : return SUCCESS;
649 : }
650 : /* }}} */
651 :
652 : #define DATE_TIMEZONEDB php_date_global_timezone_db ? php_date_global_timezone_db : timelib_builtin_db()
653 :
654 : /*
655 : * RFC822, Section 5.1: http://www.ietf.org/rfc/rfc822.txt
656 : * date-time = [ day "," ] date time ; dd mm yy hh:mm:ss zzz
657 : * day = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"
658 : * date = 1*2DIGIT month 2DIGIT ; day month year e.g. 20 Jun 82
659 : * month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
660 : * time = hour zone ; ANSI and Military
661 : * hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT] ; 00:00:00 - 23:59:59
662 : * zone = "UT" / "GMT" / "EST" / "EDT" / "CST" / "CDT" / "MST" / "MDT" / "PST" / "PDT" / 1ALPHA / ( ("+" / "-") 4DIGIT )
663 : */
664 : #define DATE_FORMAT_RFC822 "D, d M y H:i:s O"
665 :
666 : /*
667 : * RFC850, Section 2.1.4: http://www.ietf.org/rfc/rfc850.txt
668 : * Format must be acceptable both to the ARPANET and to the getdate routine.
669 : * One format that is acceptable to both is Weekday, DD-Mon-YY HH:MM:SS TIMEZONE
670 : * TIMEZONE can be any timezone name (3 or more letters)
671 : */
672 : #define DATE_FORMAT_RFC850 "l, d-M-y H:i:s T"
673 :
674 : /*
675 : * RFC1036, Section 2.1.2: http://www.ietf.org/rfc/rfc1036.txt
676 : * Its format must be acceptable both in RFC-822 and to the getdate(3)
677 : * Wdy, DD Mon YY HH:MM:SS TIMEZONE
678 : * There is no hope of having a complete list of timezones. Universal
679 : * Time (GMT), the North American timezones (PST, PDT, MST, MDT, CST,
680 : * CDT, EST, EDT) and the +/-hhmm offset specifed in RFC-822 should be supported.
681 : */
682 : #define DATE_FORMAT_RFC1036 "D, d M y H:i:s O"
683 :
684 : /*
685 : * RFC1123, Section 5.2.14: http://www.ietf.org/rfc/rfc1123.txt
686 : * RFC-822 Date and Time Specification: RFC-822 Section 5
687 : * The syntax for the date is hereby changed to: date = 1*2DIGIT month 2*4DIGIT
688 : */
689 : #define DATE_FORMAT_RFC1123 "D, d M Y H:i:s O"
690 :
691 : /*
692 : * RFC2822, Section 3.3: http://www.ietf.org/rfc/rfc2822.txt
693 : * FWS = ([*WSP CRLF] 1*WSP) / ; Folding white space
694 : * CFWS = *([FWS] comment) (([FWS] comment) / FWS)
695 : *
696 : * date-time = [ day-of-week "," ] date FWS time [CFWS]
697 : * day-of-week = ([FWS] day-name)
698 : * day-name = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"
699 : * date = day month year
700 : * year = 4*DIGIT
701 : * month = (FWS month-name FWS)
702 : * month-name = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
703 : * day = ([FWS] 1*2DIGIT)
704 : * time = time-of-day FWS zone
705 : * time-of-day = hour ":" minute [ ":" second ]
706 : * hour = 2DIGIT
707 : * minute = 2DIGIT
708 : * second = 2DIGIT
709 : * zone = (( "+" / "-" ) 4DIGIT)
710 : */
711 : #define DATE_FORMAT_RFC2822 "D, d M Y H:i:s O"
712 : /*
713 : * RFC3339, Section 5.6: http://www.ietf.org/rfc/rfc3339.txt
714 : * date-fullyear = 4DIGIT
715 : * date-month = 2DIGIT ; 01-12
716 : * date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on month/year
717 : *
718 : * time-hour = 2DIGIT ; 00-23
719 : * time-minute = 2DIGIT ; 00-59
720 : * time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second rules
721 : *
722 : * time-secfrac = "." 1*DIGIT
723 : * time-numoffset = ("+" / "-") time-hour ":" time-minute
724 : * time-offset = "Z" / time-numoffset
725 : *
726 : * partial-time = time-hour ":" time-minute ":" time-second [time-secfrac]
727 : * full-date = date-fullyear "-" date-month "-" date-mday
728 : * full-time = partial-time time-offset
729 : *
730 : * date-time = full-date "T" full-time
731 : */
732 : #define DATE_FORMAT_RFC3339 "Y-m-d\\TH:i:sP"
733 :
734 : #define DATE_FORMAT_ISO8601 "Y-m-d\\TH:i:sO"
735 :
736 : #define DATE_TZ_ERRMSG \
737 : "It is not safe to rely on the system's timezone settings. You are " \
738 : "*required* to use the date.timezone setting or the " \
739 : "date_default_timezone_set() function. In case you used any of those " \
740 : "methods and you are still getting this warning, you most likely " \
741 : "misspelled the timezone identifier. "
742 :
743 : #define SUNFUNCS_RET_TIMESTAMP 0
744 : #define SUNFUNCS_RET_STRING 1
745 : #define SUNFUNCS_RET_DOUBLE 2
746 :
747 :
748 : /* {{{ PHP_MINIT_FUNCTION */
749 : PHP_MINIT_FUNCTION(date)
750 17007 : {
751 17007 : REGISTER_INI_ENTRIES();
752 17007 : date_register_classes(TSRMLS_C);
753 : /*
754 : * RFC4287, Section 3.3: http://www.ietf.org/rfc/rfc4287.txt
755 : * A Date construct is an element whose content MUST conform to the
756 : * "date-time" production in [RFC3339]. In addition, an uppercase "T"
757 : * character MUST be used to separate date and time, and an uppercase
758 : * "Z" character MUST be present in the absence of a numeric time zone offset.
759 : */
760 17007 : REGISTER_STRING_CONSTANT("DATE_ATOM", DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
761 : /*
762 : * Preliminary specification: http://wp.netscape.com/newsref/std/cookie_spec.html
763 : * "This is based on RFC 822, RFC 850, RFC 1036, and RFC 1123,
764 : * with the variations that the only legal time zone is GMT
765 : * and the separators between the elements of the date must be dashes."
766 : */
767 17007 : REGISTER_STRING_CONSTANT("DATE_COOKIE", DATE_FORMAT_RFC850, CONST_CS | CONST_PERSISTENT);
768 17007 : REGISTER_STRING_CONSTANT("DATE_ISO8601", DATE_FORMAT_ISO8601, CONST_CS | CONST_PERSISTENT);
769 17007 : REGISTER_STRING_CONSTANT("DATE_RFC822", DATE_FORMAT_RFC822, CONST_CS | CONST_PERSISTENT);
770 17007 : REGISTER_STRING_CONSTANT("DATE_RFC850", DATE_FORMAT_RFC850, CONST_CS | CONST_PERSISTENT);
771 17007 : REGISTER_STRING_CONSTANT("DATE_RFC1036", DATE_FORMAT_RFC1036, CONST_CS | CONST_PERSISTENT);
772 17007 : REGISTER_STRING_CONSTANT("DATE_RFC1123", DATE_FORMAT_RFC1123, CONST_CS | CONST_PERSISTENT);
773 17007 : REGISTER_STRING_CONSTANT("DATE_RFC2822", DATE_FORMAT_RFC2822, CONST_CS | CONST_PERSISTENT);
774 17007 : REGISTER_STRING_CONSTANT("DATE_RFC3339", DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
775 : /*
776 : * RSS 2.0 Specification: http://blogs.law.harvard.edu/tech/rss
777 : * "All date-times in RSS conform to the Date and Time Specification of RFC 822,
778 : * with the exception that the year may be expressed with two characters or four characters (four preferred)"
779 : */
780 17007 : REGISTER_STRING_CONSTANT("DATE_RSS", DATE_FORMAT_RFC1123, CONST_CS | CONST_PERSISTENT);
781 17007 : REGISTER_STRING_CONSTANT("DATE_W3C", DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
782 :
783 17007 : REGISTER_LONG_CONSTANT("SUNFUNCS_RET_TIMESTAMP", SUNFUNCS_RET_TIMESTAMP, CONST_CS | CONST_PERSISTENT);
784 17007 : REGISTER_LONG_CONSTANT("SUNFUNCS_RET_STRING", SUNFUNCS_RET_STRING, CONST_CS | CONST_PERSISTENT);
785 17007 : REGISTER_LONG_CONSTANT("SUNFUNCS_RET_DOUBLE", SUNFUNCS_RET_DOUBLE, CONST_CS | CONST_PERSISTENT);
786 :
787 17007 : php_date_global_timezone_db = NULL;
788 17007 : php_date_global_timezone_db_enabled = 0;
789 :
790 17007 : DATEG(last_errors) = NULL;
791 17007 : return SUCCESS;
792 : }
793 : /* }}} */
794 :
795 : /* {{{ PHP_MSHUTDOWN_FUNCTION */
796 : PHP_MSHUTDOWN_FUNCTION(date)
797 17039 : {
798 17039 : UNREGISTER_INI_ENTRIES();
799 :
800 17039 : if (DATEG(last_errors)) {
801 0 : timelib_error_container_dtor(DATEG(last_errors));
802 : }
803 :
804 17039 : return SUCCESS;
805 : }
806 : /* }}} */
807 :
808 : /* {{{ PHP_MINFO_FUNCTION */
809 : PHP_MINFO_FUNCTION(date)
810 44 : {
811 44 : const timelib_tzdb *tzdb = DATE_TIMEZONEDB;
812 :
813 44 : php_info_print_table_start();
814 44 : php_info_print_table_row(2, "date/time support", "enabled");
815 44 : php_info_print_table_row(2, "\"Olson\" Timezone Database Version", tzdb->version);
816 44 : php_info_print_table_row(2, "Timezone Database", php_date_global_timezone_db_enabled ? "external" : "internal");
817 44 : php_info_print_table_row(2, "Default timezone", guess_timezone(tzdb TSRMLS_CC));
818 44 : php_info_print_table_end();
819 :
820 44 : DISPLAY_INI_ENTRIES();
821 44 : }
822 : /* }}} */
823 :
824 : /* {{{ Timezone Cache functions */
825 : static timelib_tzinfo *php_date_parse_tzfile(char *formal_tzname, const timelib_tzdb *tzdb TSRMLS_DC)
826 7566 : {
827 : timelib_tzinfo *tzi, **ptzi;
828 :
829 7566 : if(!DATEG(tzcache)) {
830 445 : ALLOC_HASHTABLE(DATEG(tzcache));
831 445 : zend_hash_init(DATEG(tzcache), 4, NULL, _php_date_tzinfo_dtor, 0);
832 : }
833 :
834 7566 : if (zend_hash_find(DATEG(tzcache), formal_tzname, strlen(formal_tzname) + 1, (void **) &ptzi) == SUCCESS) {
835 6933 : return *ptzi;
836 : }
837 :
838 633 : tzi = timelib_parse_tzfile(formal_tzname, tzdb);
839 633 : if (tzi) {
840 588 : zend_hash_add(DATEG(tzcache), formal_tzname, strlen(formal_tzname) + 1, (void *) &tzi, sizeof(timelib_tzinfo*), NULL);
841 : }
842 633 : return tzi;
843 : }
844 : /* }}} */
845 :
846 : /* {{{ Helper functions */
847 : static char* guess_timezone(const timelib_tzdb *tzdb TSRMLS_DC)
848 7496 : {
849 : /* Checking configure timezone */
850 7496 : if (DATEG(timezone) && (strlen(DATEG(timezone)) > 0)) {
851 6807 : return DATEG(timezone);
852 : }
853 : /* Check config setting for default timezone */
854 689 : if (!DATEG(default_timezone)) {
855 : /* Special case: ext/date wasn't initialized yet */
856 : zval ztz;
857 :
858 0 : if (SUCCESS == zend_get_configuration_directive("date.timezone", sizeof("date.timezone"), &ztz) &&
859 : Z_TYPE(ztz) == IS_STRING &&
860 : Z_STRLEN(ztz) > 0 &&
861 : timelib_timezone_id_is_valid(Z_STRVAL(ztz), tzdb)) {
862 0 : return Z_STRVAL(ztz);
863 : }
864 689 : } else if (*DATEG(default_timezone) && timelib_timezone_id_is_valid(DATEG(default_timezone), tzdb)) {
865 679 : return DATEG(default_timezone);
866 : }
867 : #if HAVE_TM_ZONE
868 : /* Try to guess timezone from system information */
869 : {
870 : struct tm *ta, tmbuf;
871 : time_t the_time;
872 10 : char *tzid = NULL;
873 :
874 10 : the_time = time(NULL);
875 10 : ta = php_localtime_r(&the_time, &tmbuf);
876 10 : if (ta) {
877 10 : tzid = timelib_timezone_id_from_abbr(ta->tm_zone, ta->tm_gmtoff, ta->tm_isdst);
878 : }
879 10 : if (! tzid) {
880 0 : tzid = "UTC";
881 : }
882 :
883 10 : php_error_docref(NULL TSRMLS_CC, E_WARNING, DATE_TZ_ERRMSG "We selected '%s' for '%s/%.1f/%s' instead", tzid, ta ? ta->tm_zone : "Unknown", ta ? (float) (ta->tm_gmtoff / 3600) : 0, ta ? (ta->tm_isdst ? "DST" : "no DST") : "Unknown");
884 10 : return tzid;
885 : }
886 : #endif
887 : #ifdef PHP_WIN32
888 : {
889 : char *tzid;
890 : TIME_ZONE_INFORMATION tzi;
891 :
892 : switch (GetTimeZoneInformation(&tzi))
893 : {
894 : /* no DST or not in effect */
895 : case TIME_ZONE_ID_UNKNOWN:
896 : case TIME_ZONE_ID_STANDARD:
897 : php_win_std_time:
898 : tzid = timelib_timezone_id_from_abbr("", (tzi.Bias + tzi.StandardBias) * -60, 0);
899 : if (! tzid) {
900 : tzid = "UTC";
901 : }
902 : php_error_docref(NULL TSRMLS_CC, E_WARNING, DATE_TZ_ERRMSG "We selected '%s' for '%.1f/no DST' instead", tzid, ((tzi.Bias + tzi.StandardBias) / -60.0));
903 : break;
904 :
905 : /* DST in effect */
906 : case TIME_ZONE_ID_DAYLIGHT:
907 : /* If user has disabled DST in the control panel, Windows returns 0 here */
908 : if (tzi.DaylightBias == 0) {
909 : goto php_win_std_time;
910 : }
911 :
912 : tzid = timelib_timezone_id_from_abbr("", (tzi.Bias + tzi.DaylightBias) * -60, 1);
913 : if (! tzid) {
914 : tzid = "UTC";
915 : }
916 : php_error_docref(NULL TSRMLS_CC, E_WARNING, DATE_TZ_ERRMSG "We selected '%s' for '%.1f/DST' instead", tzid, ((tzi.Bias + tzi.DaylightBias) / -60.0));
917 : break;
918 : }
919 : return tzid;
920 : }
921 : #elif defined(NETWARE)
922 : /* Try to guess timezone from system information */
923 : {
924 : char *tzid = timelib_timezone_id_from_abbr("", ((_timezone * -1) + (daylightOffset * daylightOnOff)), daylightOnOff);
925 : if (tzid) {
926 : return tzid;
927 : }
928 : }
929 : #endif
930 : /* Fallback to UTC */
931 : php_error_docref(NULL TSRMLS_CC, E_WARNING, DATE_TZ_ERRMSG "We had to select 'UTC' because your platform doesn't provide functionality for the guessing algorithm");
932 : return "UTC";
933 : }
934 :
935 : PHPAPI timelib_tzinfo *get_timezone_info(TSRMLS_D)
936 7452 : {
937 : char *tz;
938 : timelib_tzinfo *tzi;
939 :
940 7452 : tz = guess_timezone(DATE_TIMEZONEDB TSRMLS_CC);
941 7452 : tzi = php_date_parse_tzfile(tz, DATE_TIMEZONEDB TSRMLS_CC);
942 7452 : if (! tzi) {
943 0 : php_error_docref(NULL TSRMLS_CC, E_ERROR, "Timezone database is corrupt - this should *never* happen!");
944 : }
945 7452 : return tzi;
946 : }
947 : /* }}} */
948 :
949 :
950 : /* {{{ date() and gmdate() data */
951 : #include "ext/standard/php_smart_str.h"
952 :
953 : static char *mon_full_names[] = {
954 : "January", "February", "March", "April",
955 : "May", "June", "July", "August",
956 : "September", "October", "November", "December"
957 : };
958 :
959 : static char *mon_short_names[] = {
960 : "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
961 : };
962 :
963 : static char *day_full_names[] = {
964 : "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
965 : };
966 :
967 : static char *day_short_names[] = {
968 : "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
969 : };
970 :
971 : static char *am_pm_lower_names[] = { "am", "pm" };
972 : static char *am_pm_upper_names[] = { "AM", "PM" };
973 :
974 : static char *english_suffix(timelib_sll number)
975 37 : {
976 37 : if (number >= 10 && number <= 19) {
977 12 : return "th";
978 : } else {
979 25 : switch (number % 10) {
980 5 : case 1: return "st";
981 2 : case 2: return "nd";
982 2 : case 3: return "rd";
983 : }
984 : }
985 16 : return "th";
986 : }
987 : /* }}} */
988 :
989 : /* {{{ day of week helpers */
990 : char *php_date_full_day_name(timelib_sll y, timelib_sll m, timelib_sll d)
991 74 : {
992 74 : timelib_sll day_of_week = timelib_day_of_week(y, m, d);
993 74 : if (day_of_week < 0) {
994 0 : return "Unknown";
995 : }
996 74 : return day_full_names[day_of_week];
997 : }
998 :
999 : char *php_date_short_day_name(timelib_sll y, timelib_sll m, timelib_sll d)
1000 35 : {
1001 35 : timelib_sll day_of_week = timelib_day_of_week(y, m, d);
1002 35 : if (day_of_week < 0) {
1003 0 : return "Unknown";
1004 : }
1005 35 : return day_short_names[day_of_week];
1006 : }
1007 : /* }}} */
1008 :
1009 : /* {{{ date_format - (gm)date helper */
1010 :
1011 : typedef struct {
1012 : int day_shortname_lengths[7];
1013 : int day_fullname_lengths[7];
1014 : int month_shortname_lengths[12];
1015 : int month_fullname_lengths[12];
1016 : int am_pm_lenghts[2];
1017 :
1018 : char* day_shortname[7];
1019 : char* day_fullname[7];
1020 : char* month_shortname[12];
1021 : char* month_fullname[12];
1022 : char* am_pm_name[2];
1023 : } php_locale_data;
1024 :
1025 : static const UChar sLongPat [] = { 0x004D, 0x004D, 0x004D, 0x004D, 0x0020,
1026 : 0x0079, 0x0079, 0x0079, 0x0079 };
1027 :
1028 :
1029 : #define DATE_LOC_READ(type, var, cor) \
1030 : count = udat_countSymbols(fmt, (type)); \
1031 : for (i = 0 - (cor); i < count; i++) { \
1032 : array[i] = (UChar *) malloc(sizeof(UChar) * 15); \
1033 : \
1034 : status = U_ZERO_ERROR; \
1035 : j = udat_getSymbols(fmt, (type), i, array[i], 15, &status); \
1036 : \
1037 : tmp->var[i + (cor)] = (char*)array[i]; \
1038 : }
1039 :
1040 : static php_locale_data* date_get_locale_data(char *locale)
1041 4804 : {
1042 4804 : php_locale_data *tmp = malloc(sizeof(php_locale_data));
1043 : UDateFormat *fmt;
1044 4804 : UErrorCode status = 0;
1045 : int32_t count, i, j;
1046 : UChar *array[15];
1047 4804 : UChar *pat = (UChar*)sLongPat;
1048 4804 : int32_t len = 9;
1049 :
1050 4804 : fmt = udat_open(UDAT_IGNORE,UDAT_IGNORE, locale, NULL, 0, pat, len, &status);
1051 :
1052 4804 : DATE_LOC_READ(UDAT_WEEKDAYS, day_fullname, -1);
1053 4804 : DATE_LOC_READ(UDAT_SHORT_WEEKDAYS, day_shortname, -1);
1054 4804 : DATE_LOC_READ(UDAT_MONTHS, month_fullname, 0);
1055 4804 : DATE_LOC_READ(UDAT_SHORT_MONTHS, month_shortname, 0);
1056 4804 : DATE_LOC_READ(UDAT_AM_PMS, am_pm_name, 0);
1057 :
1058 4804 : udat_close(fmt);
1059 :
1060 4804 : return tmp;
1061 : }
1062 :
1063 : static void date_free_locale_data(php_locale_data *data)
1064 4804 : {
1065 : int i;
1066 38432 : for (i = 0; i < 7; ++i) {
1067 33628 : free(data->day_shortname[i]);
1068 33628 : free(data->day_fullname[i]);
1069 : }
1070 62452 : for (i = 0; i < 12; ++i) {
1071 57648 : free(data->month_shortname[i]);
1072 57648 : free(data->month_fullname[i]);
1073 : }
1074 4804 : free(data->am_pm_name[0]);
1075 4804 : free(data->am_pm_name[1]);
1076 4804 : free(data);
1077 4804 : }
1078 :
1079 : static inline int date_spprintf(char **str, size_t size TSRMLS_DC, const char *format, ...)
1080 32580 : {
1081 : int c;
1082 : va_list ap;
1083 :
1084 32580 : va_start(ap, format);
1085 :
1086 32580 : c = vuspprintf((UChar**)str, size, format, ap) * sizeof(UChar);
1087 32580 : va_end(ap);
1088 32580 : return c;
1089 : }
1090 :
1091 : #define dayname_short(s,l) s < 0 ? "Unknown" : (l ? loc_dat->day_shortname[s] : day_short_names[s])
1092 : #define dayname_full(s,l) s < 0 ? "Unknown" : (l ? loc_dat->day_fullname[s] : day_full_names[s])
1093 : #define monthname_short(s,l) l ? loc_dat->month_shortname[s] : mon_short_names[s]
1094 : #define monthname_full(s,l) l ? loc_dat->month_fullname[s] : mon_full_names[s]
1095 : #define am_pm_lower_full(s,l) l ? loc_dat->am_pm_name[s] : am_pm_lower_names[s]
1096 : #define am_pm_upper_full(s,l) l ? loc_dat->am_pm_name[s] : am_pm_upper_names[s]
1097 :
1098 : static UChar *date_format(char *format, int format_len, int *return_len, timelib_time *t, int localtime, int localized TSRMLS_DC)
1099 4845 : {
1100 4845 : smart_str string = {0};
1101 : int i, no_free, length;
1102 : char *buffer;
1103 4845 : timelib_time_offset *offset = NULL;
1104 : timelib_sll isoweek, isoyear;
1105 : php_locale_data *loc_dat;
1106 : int rfc_colon;
1107 :
1108 4845 : if (!format_len) {
1109 41 : *return_len = 0;
1110 41 : return eustrdup(EMPTY_STR);
1111 : }
1112 :
1113 4804 : loc_dat = date_get_locale_data(UG(default_locale));
1114 :
1115 4804 : if (localtime) {
1116 3510 : if (t->zone_type == TIMELIB_ZONETYPE_ABBR) {
1117 26 : offset = timelib_time_offset_ctor();
1118 26 : offset->offset = (t->z - (t->dst * 60)) * -60;
1119 26 : offset->leap_secs = 0;
1120 26 : offset->is_dst = t->dst;
1121 26 : offset->abbr = strdup(t->tz_abbr);
1122 3484 : } else if (t->zone_type == TIMELIB_ZONETYPE_OFFSET) {
1123 55 : offset = timelib_time_offset_ctor();
1124 55 : offset->offset = (t->z) * -60;
1125 55 : offset->leap_secs = 0;
1126 55 : offset->is_dst = 0;
1127 55 : offset->abbr = malloc(9); /* GMT±xxxx\0 */
1128 55 : snprintf(offset->abbr, 9, "GMT%c%02d%02d",
1129 : localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
1130 : localtime ? abs(offset->offset / 3600) : 0,
1131 : localtime ? abs((offset->offset % 3600) / 60) : 0 );
1132 : } else {
1133 3429 : offset = timelib_get_time_zone_info(t->sse, t->tz_info);
1134 : }
1135 : }
1136 4804 : timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear);
1137 :
1138 37384 : for (i = 0; i < format_len; i++) {
1139 32580 : no_free = 0;
1140 32580 : rfc_colon = 0;
1141 32580 : switch (format[i]) {
1142 : /* day */
1143 2307 : case 'd': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%02d", (int) t->d); break;
1144 210 : case 'D': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%R", localized ? IS_UNICODE : IS_STRING, dayname_short(timelib_day_of_week(t->y, t->m, t->d), localized)); break;
1145 83 : case 'j': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%d", (int) t->d); break;
1146 236 : case 'l': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%R", localized ? IS_UNICODE : IS_STRING, dayname_full(timelib_day_of_week(t->y, t->m, t->d), localized)); break;
1147 37 : case 'S': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%s", english_suffix(t->d)); break;
1148 12 : case 'w': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%d", (int) timelib_day_of_week(t->y, t->m, t->d)); break;
1149 4 : case 'N': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%d", (int) timelib_iso_day_of_week(t->y, t->m, t->d)); break;
1150 6 : case 'z': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%d", (int) timelib_day_of_year(t->y, t->m, t->d)); break;
1151 :
1152 : /* week */
1153 1040 : case 'W': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%02d", (int) isoweek); break; /* iso weeknr */
1154 1026 : case 'o': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%d", (int) isoyear); break; /* iso year */
1155 :
1156 : /* month */
1157 52 : case 'F': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%R", localized ? IS_UNICODE : IS_STRING, monthname_full(t->m - 1, localized)); break;
1158 2190 : case 'm': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%02d", (int) t->m); break;
1159 191 : case 'M': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%R", localized ? IS_UNICODE : IS_STRING, monthname_short(t->m - 1, localized)); break;
1160 18 : case 'n': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%d", (int) t->m); break;
1161 20 : case 't': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%d", (int) timelib_days_in_month(t->y, t->m)); break;
1162 :
1163 : /* year */
1164 10 : case 'L': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%d", timelib_is_leap((int) t->y)); break;
1165 71 : case 'y': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%02d", (int) t->y % 100); break;
1166 2370 : case 'Y': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%s%04lld", t->y < 0 ? "-" : "", llabs(t->y)); break;
1167 :
1168 : /* time */
1169 39 : case 'a': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%R", localized ? IS_UNICODE : IS_STRING, am_pm_lower_full(t->h >= 12 ? 1 : 0, localized)); break;
1170 7 : case 'A': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%R", localized ? IS_UNICODE : IS_STRING, am_pm_upper_full(t->h >= 12 ? 1 : 0, localized)); break;
1171 : case 'B': {
1172 6 : int retval = (((((long)t->sse)-(((long)t->sse) - ((((long)t->sse) % 86400) + 3600))) * 10) / 864);
1173 12 : while (retval < 0) {
1174 0 : retval += 1000;
1175 : }
1176 6 : retval = retval % 1000;
1177 6 : length = date_spprintf(&buffer, 32 TSRMLS_CC, "%03d", retval);
1178 6 : break;
1179 : }
1180 35 : case 'g': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%d", (t->h % 12) ? (int) t->h % 12 : 12); break;
1181 12 : case 'G': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%d", (int) t->h); break;
1182 23 : case 'h': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%02d", (t->h % 12) ? (int) t->h % 12 : 12); break;
1183 2310 : case 'H': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%02d", (int) t->h); break;
1184 2363 : case 'i': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%02d", (int) t->i); break;
1185 2352 : case 's': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%02d", (int) t->s); break;
1186 8 : case 'u': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%06d", (int) floor(t->f * 1000000)); break;
1187 :
1188 : /* timezone */
1189 123 : case 'I': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%d", localtime ? offset->is_dst : 0); break;
1190 27 : case 'P': rfc_colon = 1; /* break intentionally missing */
1191 1462 : case 'O': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%c%02d%s%02d",
1192 : localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
1193 : localtime ? abs(offset->offset / 3600) : 0,
1194 : rfc_colon ? ":" : "",
1195 : localtime ? abs((offset->offset % 3600) / 60) : 0
1196 : );
1197 1462 : break;
1198 247 : case 'T': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%s", localtime ? offset->abbr : "GMT"); break;
1199 21 : case 'e': if (!localtime) {
1200 4 : length = date_spprintf(&buffer, 32 TSRMLS_CC, "%s", "UTC");
1201 : } else {
1202 17 : switch (t->zone_type) {
1203 : case TIMELIB_ZONETYPE_ID:
1204 12 : length = date_spprintf(&buffer, 32 TSRMLS_CC, "%s", t->tz_info->name);
1205 12 : break;
1206 : case TIMELIB_ZONETYPE_ABBR:
1207 0 : length = date_spprintf(&buffer, 32 TSRMLS_CC, "%s", offset->abbr);
1208 0 : break;
1209 : case TIMELIB_ZONETYPE_OFFSET:
1210 5 : length = date_spprintf(&buffer, 32 TSRMLS_CC, "%c%02d:%02d",
1211 : ((offset->offset < 0) ? '-' : '+'),
1212 : abs(offset->offset / 3600),
1213 : abs((offset->offset % 3600) / 60)
1214 : );
1215 : break;
1216 : }
1217 : }
1218 21 : break;
1219 5 : case 'Z': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%d", localtime ? offset->offset : 0); break;
1220 :
1221 : /* full date/time */
1222 11 : case 'c': length = date_spprintf(&buffer, 96 TSRMLS_CC, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
1223 : (int) t->y, (int) t->m, (int) t->d,
1224 : (int) t->h, (int) t->i, (int) t->s,
1225 : localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
1226 : localtime ? abs(offset->offset / 3600) : 0,
1227 : localtime ? abs((offset->offset % 3600) / 60) : 0
1228 : );
1229 11 : break;
1230 35 : case 'r': length = date_spprintf(&buffer, 96 TSRMLS_CC, "%3s, %02d %3s %04d %02d:%02d:%02d %c%02d%02d",
1231 : php_date_short_day_name(t->y, t->m, t->d),
1232 : (int) t->d, mon_short_names[t->m - 1],
1233 : (int) t->y, (int) t->h, (int) t->i, (int) t->s,
1234 : localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
1235 : localtime ? abs(offset->offset / 3600) : 0,
1236 : localtime ? abs((offset->offset % 3600) / 60) : 0
1237 : );
1238 35 : break;
1239 18 : case 'U': length = date_spprintf(&buffer, 32 TSRMLS_CC, "%lld", (timelib_sll) t->sse); break;
1240 :
1241 1436 : case '\\': if (i < format_len) i++; length = date_spprintf(&buffer, 32 TSRMLS_CC, "%c", format[i]); break;
1242 :
1243 12184 : default: length = date_spprintf(&buffer, 32 TSRMLS_CC, "%c", format[i]);
1244 : break;
1245 : }
1246 32580 : smart_str_appendl(&string, buffer, length);
1247 32580 : if (!no_free) {
1248 32580 : efree(buffer);
1249 : }
1250 : }
1251 :
1252 4804 : smart_str_0(&string);
1253 4804 : date_free_locale_data(loc_dat);
1254 :
1255 4804 : if (localtime) {
1256 3510 : timelib_time_offset_dtor(offset);
1257 : }
1258 :
1259 4804 : *return_len = string.len / 2;
1260 4804 : return (UChar*) string.c;
1261 : }
1262 :
1263 : static void php_date(INTERNAL_FUNCTION_PARAMETERS, int localtime)
1264 3110 : {
1265 : char *format;
1266 : int format_len;
1267 : long ts;
1268 : UChar *string;
1269 :
1270 3110 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &format, &format_len, &ts) == FAILURE) {
1271 44 : RETURN_FALSE;
1272 : }
1273 3066 : if (ZEND_NUM_ARGS() == 1) {
1274 170 : ts = time(NULL);
1275 : }
1276 :
1277 3066 : string = php_format_date(format, format_len, ts, localtime TSRMLS_CC);
1278 :
1279 3066 : RETVAL_UNICODE(string, 0);
1280 : }
1281 : /* }}} */
1282 :
1283 : PHPAPI UChar *php_format_date(char *format, int format_len, time_t ts, int localtime TSRMLS_DC) /* {{{ */
1284 4179 : {
1285 : timelib_time *t;
1286 : timelib_tzinfo *tzi;
1287 : UChar *string;
1288 : int return_len;
1289 :
1290 4179 : t = timelib_time_ctor();
1291 :
1292 4179 : if (localtime) {
1293 2869 : tzi = get_timezone_info(TSRMLS_C);
1294 2869 : t->tz_info = tzi;
1295 2869 : t->zone_type = TIMELIB_ZONETYPE_ID;
1296 2869 : timelib_unixtime2local(t, ts);
1297 : } else {
1298 1310 : tzi = NULL;
1299 1310 : timelib_unixtime2gmt(t, ts);
1300 : }
1301 :
1302 4179 : string = date_format(format, format_len, &return_len, t, localtime, 0 TSRMLS_CC);
1303 :
1304 4179 : timelib_time_dtor(t);
1305 4179 : return string;
1306 : }
1307 : /* }}} */
1308 :
1309 : /* {{{ php_idate
1310 : */
1311 : PHPAPI int php_idate(char format, time_t ts, int localtime)
1312 85 : {
1313 : timelib_time *t;
1314 : timelib_tzinfo *tzi;
1315 85 : int retval = -1;
1316 85 : timelib_time_offset *offset = NULL;
1317 : timelib_sll isoweek, isoyear;
1318 :
1319 85 : t = timelib_time_ctor();
1320 :
1321 85 : if (!localtime) {
1322 : TSRMLS_FETCH();
1323 85 : tzi = get_timezone_info(TSRMLS_C);
1324 85 : t->tz_info = tzi;
1325 85 : t->zone_type = TIMELIB_ZONETYPE_ID;
1326 85 : timelib_unixtime2local(t, ts);
1327 : } else {
1328 0 : tzi = NULL;
1329 0 : timelib_unixtime2gmt(t, ts);
1330 : }
1331 :
1332 85 : if (!localtime) {
1333 85 : if (t->zone_type == TIMELIB_ZONETYPE_ABBR) {
1334 0 : offset = timelib_time_offset_ctor();
1335 0 : offset->offset = (t->z - (t->dst * 60)) * -60;
1336 0 : offset->leap_secs = 0;
1337 0 : offset->is_dst = t->dst;
1338 0 : offset->abbr = strdup(t->tz_abbr);
1339 85 : } else if (t->zone_type == TIMELIB_ZONETYPE_OFFSET) {
1340 0 : offset = timelib_time_offset_ctor();
1341 0 : offset->offset = (t->z - (t->dst * 60)) * -60;
1342 0 : offset->leap_secs = 0;
1343 0 : offset->is_dst = t->dst;
1344 0 : offset->abbr = malloc(9); /* GMT±xxxx\0 */
1345 0 : snprintf(offset->abbr, 9, "GMT%c%02d%02d",
1346 : !localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
1347 : !localtime ? abs(offset->offset / 3600) : 0,
1348 : !localtime ? abs((offset->offset % 3600) / 60) : 0 );
1349 : } else {
1350 85 : offset = timelib_get_time_zone_info(t->sse, t->tz_info);
1351 : }
1352 : }
1353 :
1354 85 : timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear);
1355 :
1356 85 : switch (format) {
1357 : /* day */
1358 4 : case 'd': case 'j': retval = (int) t->d; break;
1359 :
1360 3 : case 'w': retval = (int) timelib_day_of_week(t->y, t->m, t->d); break;
1361 3 : case 'z': retval = (int) timelib_day_of_year(t->y, t->m, t->d); break;
1362 :
1363 : /* week */
1364 3 : case 'W': retval = (int) isoweek; break; /* iso weeknr */
1365 :
1366 : /* month */
1367 4 : case 'm': case 'n': retval = (int) t->m; break;
1368 3 : case 't': retval = (int) timelib_days_in_month(t->y, t->m); break;
1369 :
1370 : /* year */
1371 3 : case 'L': retval = (int) timelib_is_leap((int) t->y); break;
1372 5 : case 'y': retval = (int) (t->y % 100); break;
1373 19 : case 'Y': retval = (int) t->y; break;
1374 :
1375 : /* Swatch Beat a.k.a. Internet Time */
1376 : case 'B':
1377 4 : retval = (((((long)t->sse)-(((long)t->sse) - ((((long)t->sse) % 86400) + 3600))) * 10) / 864);
1378 8 : while (retval < 0) {
1379 0 : retval += 1000;
1380 : }
1381 4 : retval = retval % 1000;
1382 4 : break;
1383 :
1384 : /* time */
1385 4 : case 'g': case 'h': retval = (int) ((t->h % 12) ? (int) t->h % 12 : 12); break;
1386 4 : case 'H': case 'G': retval = (int) t->h; break;
1387 3 : case 'i': retval = (int) t->i; break;
1388 3 : case 's': retval = (int) t->s; break;
1389 :
1390 : /* timezone */
1391 3 : case 'I': retval = (int) (!localtime ? offset->is_dst : 0); break;
1392 2 : case 'Z': retval = (int) (!localtime ? offset->offset : 0); break;
1393 :
1394 3 : case 'U': retval = (int) t->sse; break;
1395 : }
1396 :
1397 85 : if (!localtime) {
1398 85 : timelib_time_offset_dtor(offset);
1399 : }
1400 85 : timelib_time_dtor(t);
1401 :
1402 85 : return retval;
1403 : }
1404 : /* }}} */
1405 :
1406 : /* {{{ proto string date(string format [, long timestamp]) U
1407 : Format a local date/time */
1408 : PHP_FUNCTION(date)
1409 2889 : {
1410 2889 : php_date(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1411 2889 : }
1412 : /* }}} */
1413 :
1414 : /* {{{ proto string gmdate(string format [, long timestamp]) U
1415 : Format a GMT date/time */
1416 : PHP_FUNCTION(gmdate)
1417 221 : {
1418 221 : php_date(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1419 221 : }
1420 : /* }}} */
1421 :
1422 : /* {{{ proto int idate(string format [, int timestamp]) U
1423 : Format a local time/date as integer */
1424 : PHP_FUNCTION(idate)
1425 144 : {
1426 : char *format;
1427 : int format_len;
1428 144 : long ts = 0;
1429 : int ret;
1430 :
1431 144 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &format, &format_len, &ts) == FAILURE) {
1432 26 : RETURN_FALSE;
1433 : }
1434 :
1435 118 : if (format_len != 1) {
1436 33 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "idate format is one char");
1437 33 : RETURN_FALSE;
1438 : }
1439 :
1440 85 : if (ZEND_NUM_ARGS() == 1) {
1441 25 : ts = time(NULL);
1442 : }
1443 :
1444 85 : ret = php_idate(format[0], ts, 0);
1445 85 : if (ret == -1) {
1446 12 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unrecognized date format token");
1447 12 : RETURN_FALSE;
1448 : }
1449 73 : RETURN_LONG(ret);
1450 : }
1451 : /* }}} */
1452 :
1453 : /* {{{ php_date_set_tzdb - NOT THREADSAFE */
1454 : PHPAPI void php_date_set_tzdb(timelib_tzdb *tzdb)
1455 0 : {
1456 0 : const timelib_tzdb *builtin = timelib_builtin_db();
1457 :
1458 0 : if (php_version_compare(tzdb->version, builtin->version) > 0) {
1459 0 : php_date_global_timezone_db = tzdb;
1460 0 : php_date_global_timezone_db_enabled = 1;
1461 : }
1462 0 : }
1463 : /* }}} */
1464 :
1465 : /* {{{ php_parse_date: Backwards compability function */
1466 : PHPAPI signed long php_parse_date(char *string, signed long *now)
1467 8 : {
1468 : timelib_time *parsed_time;
1469 : int error2;
1470 : signed long retval;
1471 :
1472 8 : parsed_time = timelib_strtotime(string, strlen(string), NULL, DATE_TIMEZONEDB);
1473 8 : timelib_update_ts(parsed_time, NULL);
1474 8 : retval = timelib_date_to_int(parsed_time, &error2);
1475 8 : timelib_time_dtor(parsed_time);
1476 8 : if (error2) {
1477 1 : return -1;
1478 : }
1479 7 : return retval;
1480 : }
1481 : /* }}} */
1482 :
1483 :
1484 : /* {{{ proto int strtotime(string time [, int now ]) U
1485 : Convert string representation of date and time to a timestamp */
1486 : PHP_FUNCTION(strtotime)
1487 2626 : {
1488 : char *times, *initial_ts;
1489 : int time_len, error1, error2;
1490 : struct timelib_error_container *error;
1491 2626 : long preset_ts = 0, ts;
1492 :
1493 : timelib_time *t, *now;
1494 : timelib_tzinfo *tzi;
1495 :
1496 2626 : tzi = get_timezone_info(TSRMLS_C);
1497 :
1498 2626 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "sl", ×, &time_len, &preset_ts) != FAILURE) {
1499 : /* We have an initial timestamp */
1500 189 : now = timelib_time_ctor();
1501 :
1502 189 : initial_ts = emalloc(25);
1503 189 : snprintf(initial_ts, 24, "@%ld UTC", preset_ts);
1504 189 : t = timelib_strtotime(initial_ts, strlen(initial_ts), NULL, DATE_TIMEZONEDB); /* we ignore the error here, as this should never fail */
1505 189 : timelib_update_ts(t, tzi);
1506 189 : now->tz_info = tzi;
1507 189 : now->zone_type = TIMELIB_ZONETYPE_ID;
1508 189 : timelib_unixtime2local(now, t->sse);
1509 189 : timelib_time_dtor(t);
1510 189 : efree(initial_ts);
1511 2437 : } else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", ×, &time_len, &preset_ts) != FAILURE) {
1512 : /* We have no initial timestamp */
1513 2437 : now = timelib_time_ctor();
1514 2437 : now->tz_info = tzi;
1515 2437 : now->zone_type = TIMELIB_ZONETYPE_ID;
1516 2437 : timelib_unixtime2local(now, (timelib_sll) time(NULL));
1517 : } else {
1518 0 : RETURN_FALSE;
1519 : }
1520 :
1521 2626 : if (!time_len) {
1522 1 : timelib_time_dtor(now);
1523 1 : RETURN_FALSE;
1524 : }
1525 :
1526 2625 : t = timelib_strtotime(times, time_len, &error, DATE_TIMEZONEDB);
1527 2625 : error1 = error->error_count;
1528 2625 : timelib_error_container_dtor(error);
1529 2625 : timelib_fill_holes(t, now, TIMELIB_NO_CLONE);
1530 2625 : timelib_update_ts(t, tzi);
1531 2625 : ts = timelib_date_to_int(t, &error2);
1532 :
1533 2625 : timelib_time_dtor(now);
1534 2625 : timelib_time_dtor(t);
1535 :
1536 2625 : if (error1 || error2) {
1537 14 : RETURN_FALSE;
1538 : } else {
1539 2611 : RETURN_LONG(ts);
1540 : }
1541 : }
1542 : /* }}} */
1543 :
1544 :
1545 : /* {{{ php_mktime - (gm)mktime helper */
1546 : PHPAPI void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
1547 990 : {
1548 990 : long hou = 0, min = 0, sec = 0, mon = 0, day = 0, yea = 0, dst = -1;
1549 : timelib_time *now;
1550 990 : timelib_tzinfo *tzi = NULL;
1551 990 : long ts, adjust_seconds = 0;
1552 : int error;
1553 :
1554 990 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lllllll", &hou, &min, &sec, &mon, &day, &yea, &dst) == FAILURE) {
1555 165 : RETURN_FALSE;
1556 : }
1557 : /* Initialize structure with current time */
1558 825 : now = timelib_time_ctor();
1559 825 : if (gmt) {
1560 117 : timelib_unixtime2gmt(now, (timelib_sll) time(NULL));
1561 : } else {
1562 708 : tzi = get_timezone_info(TSRMLS_C);
1563 708 : now->tz_info = tzi;
1564 708 : now->zone_type = TIMELIB_ZONETYPE_ID;
1565 708 : timelib_unixtime2local(now, (timelib_sll) time(NULL));
1566 : }
1567 : /* Fill in the new data */
1568 825 : switch (ZEND_NUM_ARGS()) {
1569 : case 7:
1570 : /* break intentionally missing */
1571 : case 6:
1572 768 : if (yea >= 0 && yea < 70) {
1573 25 : yea += 2000;
1574 718 : } else if (yea >= 70 && yea <= 100) {
1575 8 : yea += 1900;
1576 : }
1577 743 : now->y = yea;
1578 : /* break intentionally missing again */
1579 : case 5:
1580 759 : now->d = day;
1581 : /* break missing intentionally here too */
1582 : case 4:
1583 775 : now->m = mon;
1584 : /* and here */
1585 : case 3:
1586 791 : now->s = sec;
1587 : /* yup, this break isn't here on purpose too */
1588 : case 2:
1589 807 : now->i = min;
1590 : /* last intentionally missing break */
1591 : case 1:
1592 823 : now->h = hou;
1593 823 : break;
1594 : default:
1595 2 : php_error_docref(NULL TSRMLS_CC, E_STRICT, "You should be using the time() function instead");
1596 : }
1597 : /* Update the timestamp */
1598 825 : if (gmt) {
1599 117 : timelib_update_ts(now, NULL);
1600 : } else {
1601 708 : timelib_update_ts(now, tzi);
1602 : }
1603 : /* Support for the deprecated is_dst parameter */
1604 825 : if (dst != -1) {
1605 39 : php_error_docref(NULL TSRMLS_CC, E_DEPRECATED, "The is_dst parameter is deprecated");
1606 39 : if (gmt) {
1607 : /* GMT never uses DST */
1608 1 : if (dst == 1) {
1609 0 : adjust_seconds = -3600;
1610 : }
1611 : } else {
1612 : /* Figure out is_dst for current TS */
1613 : timelib_time_offset *tmp_offset;
1614 38 : tmp_offset = timelib_get_time_zone_info(now->sse, tzi);
1615 38 : if (dst == 1 && tmp_offset->is_dst == 0) {
1616 7 : adjust_seconds = -3600;
1617 : }
1618 38 : if (dst == 0 && tmp_offset->is_dst == 1) {
1619 13 : adjust_seconds = +3600;
1620 : }
1621 38 : timelib_time_offset_dtor(tmp_offset);
1622 : }
1623 : }
1624 : /* Clean up and return */
1625 825 : ts = timelib_date_to_int(now, &error);
1626 825 : ts += adjust_seconds;
1627 825 : timelib_time_dtor(now);
1628 :
1629 825 : if (error) {
1630 22 : RETURN_FALSE;
1631 : } else {
1632 803 : RETURN_LONG(ts);
1633 : }
1634 : }
1635 : /* }}} */
1636 :
1637 : /* {{{ proto int mktime([int hour [, int min [, int sec [, int mon [, int day [, int year]]]]]]) U
1638 : Get UNIX timestamp for a date */
1639 : PHP_FUNCTION(mktime)
1640 800 : {
1641 800 : php_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1642 800 : }
1643 : /* }}} */
1644 :
1645 : /* {{{ proto int gmmktime([int hour [, int min [, int sec [, int mon [, int day [, int year]]]]]]) U
1646 : Get UNIX timestamp for a GMT date */
1647 : PHP_FUNCTION(gmmktime)
1648 190 : {
1649 190 : php_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1650 190 : }
1651 : /* }}} */
1652 :
1653 :
1654 : /* {{{ proto bool checkdate(int month, int day, int year) U
1655 : Returns true(1) if it is a valid date in gregorian calendar */
1656 : PHP_FUNCTION(checkdate)
1657 100 : {
1658 : long m, d, y;
1659 :
1660 100 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &m, &d, &y) == FAILURE) {
1661 45 : RETURN_FALSE;
1662 : }
1663 :
1664 55 : if (y < 1 || y > 32767 || !timelib_valid_date(y, m, d)) {
1665 36 : RETURN_FALSE;
1666 : }
1667 19 : RETURN_TRUE; /* True : This month, day, year arguments are valid */
1668 : }
1669 : /* }}} */
1670 :
1671 : #ifdef HAVE_STRFTIME
1672 : /* {{{ php_strftime - (gm)strftime helper */
1673 : PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
1674 384 : {
1675 : char *format, *buf;
1676 : int format_len;
1677 384 : long timestamp = 0;
1678 : struct tm ta;
1679 384 : int max_reallocs = 5;
1680 384 : size_t buf_len = 64, real_len;
1681 : timelib_time *ts;
1682 : timelib_tzinfo *tzi;
1683 384 : timelib_time_offset *offset = NULL;
1684 :
1685 384 : timestamp = (long) time(NULL);
1686 :
1687 384 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &format, &format_len, ×tamp) == FAILURE) {
1688 49 : RETURN_FALSE;
1689 : }
1690 :
1691 335 : if (format_len == 0) {
1692 34 : RETURN_FALSE;
1693 : }
1694 :
1695 301 : ts = timelib_time_ctor();
1696 301 : if (gmt) {
1697 113 : tzi = NULL;
1698 113 : timelib_unixtime2gmt(ts, (timelib_sll) timestamp);
1699 : } else {
1700 188 : tzi = get_timezone_info(TSRMLS_C);
1701 188 : ts->tz_info = tzi;
1702 188 : ts->zone_type = TIMELIB_ZONETYPE_ID;
1703 188 : timelib_unixtime2local(ts, (timelib_sll) timestamp);
1704 : }
1705 301 : ta.tm_sec = ts->s;
1706 301 : ta.tm_min = ts->i;
1707 301 : ta.tm_hour = ts->h;
1708 301 : ta.tm_mday = ts->d;
1709 301 : ta.tm_mon = ts->m - 1;
1710 301 : ta.tm_year = ts->y - 1900;
1711 301 : ta.tm_wday = timelib_day_of_week(ts->y, ts->m, ts->d);
1712 301 : ta.tm_yday = timelib_day_of_year(ts->y, ts->m, ts->d);
1713 301 : if (gmt) {
1714 113 : ta.tm_isdst = 0;
1715 : #if HAVE_TM_GMTOFF
1716 113 : ta.tm_gmtoff = 0;
1717 : #endif
1718 : #if HAVE_TM_ZONE
1719 113 : ta.tm_zone = "GMT";
1720 : #endif
1721 : } else {
1722 188 : offset = timelib_get_time_zone_info(timestamp, tzi);
1723 :
1724 188 : ta.tm_isdst = offset->is_dst;
1725 : #if HAVE_TM_GMTOFF
1726 188 : ta.tm_gmtoff = offset->offset;
1727 : #endif
1728 : #if HAVE_TM_ZONE
1729 188 : ta.tm_zone = offset->abbr;
1730 : #endif
1731 : }
1732 :
1733 301 : buf = (char *) emalloc(buf_len);
1734 606 : while ((real_len=strftime(buf, buf_len, format, &ta))==buf_len || real_len==0) {
1735 4 : buf_len *= 2;
1736 4 : buf = (char *) erealloc(buf, buf_len);
1737 4 : if (!--max_reallocs) {
1738 0 : break;
1739 : }
1740 : }
1741 :
1742 301 : timelib_time_dtor(ts);
1743 301 : if (!gmt) {
1744 188 : timelib_time_offset_dtor(offset);
1745 : }
1746 :
1747 301 : if (real_len && real_len != buf_len) {
1748 301 : buf = (char *) erealloc(buf, real_len + 1);
1749 301 : RETVAL_RT_STRINGL(buf, real_len, 1);
1750 301 : efree(buf);
1751 301 : return;
1752 : }
1753 0 : efree(buf);
1754 0 : RETURN_FALSE;
1755 : }
1756 : /* }}} */
1757 :
1758 : /* {{{ proto string strftime(string format [, int timestamp]) U
1759 : Format a local time/date according to locale settings */
1760 : PHP_FUNCTION(strftime)
1761 229 : {
1762 229 : php_strftime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1763 229 : }
1764 : /* }}} */
1765 :
1766 : /* {{{ proto string gmstrftime(string format [, int timestamp]) U
1767 : Format a GMT/UCT time/date according to locale settings */
1768 : PHP_FUNCTION(gmstrftime)
1769 155 : {
1770 155 : php_strftime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1771 155 : }
1772 : /* }}} */
1773 : #endif
1774 :
1775 : /* {{{ proto int time(void) U
1776 : Return current UNIX timestamp */
1777 : PHP_FUNCTION(time)
1778 33339 : {
1779 33339 : RETURN_LONG((long)time(NULL));
1780 : }
1781 : /* }}} */
1782 :
1783 : /* {{{ proto array localtime([int timestamp [, bool associative_array]]) U
1784 : Returns the results of the C system call localtime as an associative array if the associative_array argument is set to 1 other wise it is a regular array */
1785 : PHP_FUNCTION(localtime)
1786 100 : {
1787 100 : long timestamp = (long)time(NULL);
1788 100 : zend_bool associative = 0;
1789 : timelib_tzinfo *tzi;
1790 : timelib_time *ts;
1791 :
1792 100 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lb", ×tamp, &associative) == FAILURE) {
1793 32 : RETURN_FALSE;
1794 : }
1795 :
1796 68 : tzi = get_timezone_info(TSRMLS_C);
1797 68 : ts = timelib_time_ctor();
1798 68 : ts->tz_info = tzi;
1799 68 : ts->zone_type = TIMELIB_ZONETYPE_ID;
1800 68 : timelib_unixtime2local(ts, (timelib_sll) timestamp);
1801 :
1802 68 : array_init(return_value);
1803 :
1804 68 : if (associative) {
1805 35 : add_ascii_assoc_long(return_value, "tm_sec", ts->s);
1806 35 : add_ascii_assoc_long(return_value, "tm_min", ts->i);
1807 35 : add_ascii_assoc_long(return_value, "tm_hour", ts->h);
1808 35 : add_ascii_assoc_long(return_value, "tm_mday", ts->d);
1809 35 : add_ascii_assoc_long(return_value, "tm_mon", ts->m - 1);
1810 35 : add_ascii_assoc_long(return_value, "tm_year", ts->y - 1900);
1811 35 : add_ascii_assoc_long(return_value, "tm_wday", timelib_day_of_week(ts->y, ts->m, ts->d));
1812 35 : add_ascii_assoc_long(return_value, "tm_yday", timelib_day_of_year(ts->y, ts->m, ts->d));
1813 35 : add_ascii_assoc_long(return_value, "tm_isdst", ts->dst);
1814 : } else {
1815 33 : add_next_index_long(return_value, ts->s);
1816 33 : add_next_index_long(return_value, ts->i);
1817 33 : add_next_index_long(return_value, ts->h);
1818 33 : add_next_index_long(return_value, ts->d);
1819 33 : add_next_index_long(return_value, ts->m - 1);
1820 33 : add_next_index_long(return_value, ts->y- 1900);
1821 33 : add_next_index_long(return_value, timelib_day_of_week(ts->y, ts->m, ts->d));
1822 33 : add_next_index_long(return_value, timelib_day_of_year(ts->y, ts->m, ts->d));
1823 33 : add_next_index_long(return_value, ts->dst);
1824 : }
1825 :
1826 68 : timelib_time_dtor(ts);
1827 : }
1828 : /* }}} */
1829 :
1830 : /* {{{ proto array getdate([int timestamp]) U
1831 : Get date/time information */
1832 : PHP_FUNCTION(getdate)
1833 51 : {
1834 51 : long timestamp = (long)time(NULL);
1835 : timelib_tzinfo *tzi;
1836 : timelib_time *ts;
1837 :
1838 51 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", ×tamp) == FAILURE) {
1839 14 : RETURN_FALSE;
1840 : }
1841 :
1842 37 : tzi = get_timezone_info(TSRMLS_C);
1843 37 : ts = timelib_time_ctor();
1844 37 : ts->tz_info = tzi;
1845 37 : ts->zone_type = TIMELIB_ZONETYPE_ID;
1846 37 : timelib_unixtime2local(ts, (timelib_sll) timestamp);
1847 :
1848 37 : array_init(return_value);
1849 :
1850 37 : add_ascii_assoc_long(return_value, "seconds", ts->s);
1851 37 : add_ascii_assoc_long(return_value, "minutes", ts->i);
1852 37 : add_ascii_assoc_long(return_value, "hours", ts->h);
1853 37 : add_ascii_assoc_long(return_value, "mday", ts->d);
1854 37 : add_ascii_assoc_long(return_value, "wday", timelib_day_of_week(ts->y, ts->m, ts->d));
1855 37 : add_ascii_assoc_long(return_value, "mon", ts->m);
1856 37 : add_ascii_assoc_long(return_value, "year", ts->y);
1857 37 : add_ascii_assoc_long(return_value, "yday", timelib_day_of_year(ts->y, ts->m, ts->d));
1858 37 : add_ascii_assoc_ascii_string(return_value, "weekday", php_date_full_day_name(ts->y, ts->m, ts->d), 1);
1859 37 : add_ascii_assoc_ascii_string(return_value, "month", mon_full_names[ts->m - 1], 1);
1860 37 : add_index_long(return_value, 0, timestamp);
1861 :
1862 37 : timelib_time_dtor(ts);
1863 : }
1864 : /* }}} */
1865 :
1866 : #define PHP_DATE_TIMEZONE_GROUP_AFRICA 0x0001
1867 : #define PHP_DATE_TIMEZONE_GROUP_AMERICA 0x0002
1868 : #define PHP_DATE_TIMEZONE_GROUP_ANTARCTICA 0x0004
1869 : #define PHP_DATE_TIMEZONE_GROUP_ARCTIC 0x0008
1870 : #define PHP_DATE_TIMEZONE_GROUP_ASIA 0x0010
1871 : #define PHP_DATE_TIMEZONE_GROUP_ATLANTIC 0x0020
1872 : #define PHP_DATE_TIMEZONE_GROUP_AUSTRALIA 0x0040
1873 : #define PHP_DATE_TIMEZONE_GROUP_EUROPE 0x0080
1874 : #define PHP_DATE_TIMEZONE_GROUP_INDIAN 0x0100
1875 : #define PHP_DATE_TIMEZONE_GROUP_PACIFIC 0x0200
1876 : #define PHP_DATE_TIMEZONE_GROUP_UTC 0x0400
1877 : #define PHP_DATE_TIMEZONE_GROUP_ALL 0x07FF
1878 : #define PHP_DATE_TIMEZONE_GROUP_ALL_W_BC 0x0FFF
1879 : #define PHP_DATE_TIMEZONE_PER_COUNTRY 0x1000
1880 :
1881 : #define PHP_DATE_PERIOD_EXCLUDE_START_DATE 0x0001
1882 :
1883 :
1884 : /* define an overloaded iterator structure */
1885 : typedef struct {
1886 : zend_object_iterator intern;
1887 : zval *date_period_zval;
1888 : zval *current;
1889 : php_period_obj *object;
1890 : int current_index;
1891 : } date_period_it;
1892 :
1893 : /* {{{ date_period_it_invalidate_current */
1894 : static void date_period_it_invalidate_current(zend_object_iterator *iter TSRMLS_DC)
1895 53 : {
1896 53 : date_period_it *iterator = (date_period_it *)iter;
1897 :
1898 53 : if (iterator->current) {
1899 47 : zval_ptr_dtor(&iterator->current);
1900 47 : iterator->current = NULL;
1901 : }
1902 53 : }
1903 : /* }}} */
1904 :
1905 :
1906 : /* {{{ date_period_it_dtor */
1907 : static void date_period_it_dtor(zend_object_iterator *iter TSRMLS_DC)
1908 3 : {
1909 3 : date_period_it *iterator = (date_period_it *)iter;
1910 :
1911 3 : date_period_it_invalidate_current(iter TSRMLS_CC);
1912 :
1913 3 : zval_ptr_dtor(&iterator->date_period_zval);
1914 :
1915 3 : efree(iterator);
1916 3 : }
1917 : /* }}} */
1918 :
1919 :
1920 : /* {{{ date_period_it_has_more */
1921 : static int date_period_it_has_more(zend_object_iterator *iter TSRMLS_DC)
1922 50 : {
1923 50 : date_period_it *iterator = (date_period_it *)iter;
1924 50 : php_period_obj *object = iterator->object;
1925 50 : timelib_time *it_time = object->start;
1926 :
1927 : /* apply modification if it's not the first iteration */
1928 50 : if (!object->include_start_date || iterator->current_index > 0) {
1929 48 : it_time->have_relative = 1;
1930 48 : it_time->relative = *object->interval;
1931 48 : it_time->sse_uptodate = 0;
1932 48 : timelib_update_ts(it_time, NULL);
1933 48 : timelib_update_from_sse(it_time);
1934 : }
1935 :
1936 50 : if (object->end) {
1937 38 : return object->start->sse < object->end->sse ? SUCCESS : FAILURE;
1938 : } else {
1939 12 : return (iterator->current_index < object->recurrences) ? SUCCESS : FAILURE;
1940 : }
1941 : }
1942 : /* }}} */
1943 :
1944 :
1945 : /* {{{ date_period_it_current_data */
1946 : static void date_period_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
1947 47 : {
1948 47 : date_period_it *iterator = (date_period_it *)iter;
1949 47 : php_period_obj *object = iterator->object;
1950 47 : timelib_time *it_time = object->start;
1951 : php_date_obj *newdateobj;
1952 :
1953 : /* Create new object */
1954 47 : MAKE_STD_ZVAL(iterator->current);
1955 47 : date_instantiate(date_ce_date, iterator->current TSRMLS_CC);
1956 47 : newdateobj = (php_date_obj *) zend_object_store_get_object(iterator->current TSRMLS_CC);
1957 47 : newdateobj->time = timelib_time_ctor();
1958 47 : *newdateobj->time = *it_time;
1959 47 : if (it_time->tz_abbr) {
1960 47 : newdateobj->time->tz_abbr = strdup(it_time->tz_abbr);
1961 : }
1962 47 : if (it_time->tz_info) {
1963 47 : newdateobj->time->tz_info = it_time->tz_info;
1964 : }
1965 :
1966 47 : *data = &iterator->current;
1967 47 : }
1968 : /* }}} */
1969 :
1970 :
1971 : /* {{{ date_period_it_current_key */
1972 : static int date_period_it_current_key(zend_object_iterator *iter, zstr *str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
1973 0 : {
1974 0 : date_period_it *iterator = (date_period_it *)iter;
1975 0 : *int_key = iterator->current_index;
1976 0 : return HASH_KEY_IS_LONG;
1977 : }
1978 : /* }}} */
1979 :
1980 :
1981 : /* {{{ date_period_it_move_forward */
1982 : static void date_period_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
1983 47 : {
1984 47 : date_period_it *iterator = (date_period_it *)iter;
1985 :
1986 47 : iterator->current_index++;
1987 47 : date_period_it_invalidate_current(iter TSRMLS_CC);
1988 47 : }
1989 : /* }}} */
1990 :
1991 :
1992 : /* {{{ date_period_it_rewind */
1993 : static void date_period_it_rewind(zend_object_iterator *iter TSRMLS_DC)
1994 3 : {
1995 3 : date_period_it *iterator = (date_period_it *)iter;
1996 :
1997 3 : iterator->current_index = 0;
1998 3 : date_period_it_invalidate_current(iter TSRMLS_CC);
1999 3 : }
2000 : /* }}} */
2001 :
2002 :
2003 : /* iterator handler table */
2004 : zend_object_iterator_funcs date_period_it_funcs = {
2005 : date_period_it_dtor,
2006 : date_period_it_has_more,
2007 : date_period_it_current_data,
2008 : date_period_it_current_key,
2009 : date_period_it_move_forward,
2010 : date_period_it_rewind,
2011 : date_period_it_invalidate_current
2012 : };
2013 :
2014 :
2015 :
2016 : zend_object_iterator *date_object_period_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
2017 3 : {
2018 3 : date_period_it *iterator = emalloc(sizeof(date_period_it));
2019 3 : php_period_obj *dpobj = (php_period_obj *)zend_object_store_get_object(object TSRMLS_CC);
2020 :
2021 3 : if (by_ref) {
2022 0 : zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
2023 : }
2024 :
2025 3 : Z_ADDREF_P(object);
2026 3 : iterator->intern.data = (void*) dpobj;
2027 3 : iterator->intern.funcs = &date_period_it_funcs;
2028 3 : iterator->date_period_zval = object;
2029 3 : iterator->object = dpobj;
2030 3 : iterator->current = NULL;
2031 :
2032 3 : return (zend_object_iterator*)iterator;
2033 : }
2034 :
2035 : static void date_register_classes(TSRMLS_D)
2036 17007 : {
2037 : zend_class_entry ce_date, ce_timezone, ce_interval, ce_period;
2038 :
2039 17007 : INIT_CLASS_ENTRY(ce_date, "DateTime", date_funcs_date);
2040 17007 : ce_date.create_object = date_object_new_date;
2041 17007 : date_ce_date = zend_register_internal_class_ex(&ce_date, NULL, NULL TSRMLS_CC);
2042 17007 : memcpy(&date_object_handlers_date, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2043 17007 : date_object_handlers_date.clone_obj = date_object_clone_date;
2044 17007 : date_object_handlers_date.compare_objects = date_object_compare_date;
2045 17007 : date_object_handlers_date.get_properties = date_object_get_properties;
2046 :
2047 : #define REGISTER_DATE_CLASS_CONST_STRING(const_name, value) \
2048 : zend_declare_class_constant_stringl(date_ce_date, const_name, sizeof(const_name)-1, value, sizeof(value)-1 TSRMLS_CC);
2049 :
2050 17007 : REGISTER_DATE_CLASS_CONST_STRING("ATOM", DATE_FORMAT_RFC3339);
2051 17007 : REGISTER_DATE_CLASS_CONST_STRING("COOKIE", DATE_FORMAT_RFC850);
2052 17007 : REGISTER_DATE_CLASS_CONST_STRING("ISO8601", DATE_FORMAT_ISO8601);
2053 17007 : REGISTER_DATE_CLASS_CONST_STRING("RFC822", DATE_FORMAT_RFC822);
2054 17007 : REGISTER_DATE_CLASS_CONST_STRING("RFC850", DATE_FORMAT_RFC850);
2055 17007 : REGISTER_DATE_CLASS_CONST_STRING("RFC1036", DATE_FORMAT_RFC1036);
2056 17007 : REGISTER_DATE_CLASS_CONST_STRING("RFC1123", DATE_FORMAT_RFC1123);
2057 17007 : REGISTER_DATE_CLASS_CONST_STRING("RFC2822", DATE_FORMAT_RFC2822);
2058 17007 : REGISTER_DATE_CLASS_CONST_STRING("RFC3339", DATE_FORMAT_RFC3339);
2059 17007 : REGISTER_DATE_CLASS_CONST_STRING("RSS", DATE_FORMAT_RFC1123);
2060 17007 : REGISTER_DATE_CLASS_CONST_STRING("W3C", DATE_FORMAT_RFC3339);
2061 :
2062 :
2063 17007 : INIT_CLASS_ENTRY(ce_timezone, "DateTimeZone", date_funcs_timezone);
2064 17007 : ce_timezone.create_object = date_object_new_timezone;
2065 17007 : date_ce_timezone = zend_register_internal_class_ex(&ce_timezone, NULL, NULL TSRMLS_CC);
2066 17007 : memcpy(&date_object_handlers_timezone, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2067 17007 : date_object_handlers_timezone.clone_obj = date_object_clone_timezone;
2068 :
2069 : #define REGISTER_TIMEZONE_CLASS_CONST_STRING(const_name, value) \
2070 : zend_declare_class_constant_long(date_ce_timezone, const_name, sizeof(const_name)-1, value TSRMLS_CC);
2071 :
2072 17007 : REGISTER_TIMEZONE_CLASS_CONST_STRING("AFRICA", PHP_DATE_TIMEZONE_GROUP_AFRICA);
2073 17007 : REGISTER_TIMEZONE_CLASS_CONST_STRING("AMERICA", PHP_DATE_TIMEZONE_GROUP_AMERICA);
2074 17007 : REGISTER_TIMEZONE_CLASS_CONST_STRING("ANTARCTICA", PHP_DATE_TIMEZONE_GROUP_ANTARCTICA);
2075 17007 : REGISTER_TIMEZONE_CLASS_CONST_STRING("ARCTIC", PHP_DATE_TIMEZONE_GROUP_ARCTIC);
2076 17007 : REGISTER_TIMEZONE_CLASS_CONST_STRING("ASIA", PHP_DATE_TIMEZONE_GROUP_ASIA);
2077 17007 : REGISTER_TIMEZONE_CLASS_CONST_STRING("ATLANTIC", PHP_DATE_TIMEZONE_GROUP_ATLANTIC);
2078 17007 : REGISTER_TIMEZONE_CLASS_CONST_STRING("AUSTRALIA", PHP_DATE_TIMEZONE_GROUP_AUSTRALIA);
2079 17007 : REGISTER_TIMEZONE_CLASS_CONST_STRING("EUROPE", PHP_DATE_TIMEZONE_GROUP_EUROPE);
2080 17007 : REGISTER_TIMEZONE_CLASS_CONST_STRING("INDIAN", PHP_DATE_TIMEZONE_GROUP_INDIAN);
2081 17007 : REGISTER_TIMEZONE_CLASS_CONST_STRING("PACIFIC", PHP_DATE_TIMEZONE_GROUP_PACIFIC);
2082 17007 : REGISTER_TIMEZONE_CLASS_CONST_STRING("UTC", PHP_DATE_TIMEZONE_GROUP_UTC);
2083 17007 : REGISTER_TIMEZONE_CLASS_CONST_STRING("ALL", PHP_DATE_TIMEZONE_GROUP_ALL);
2084 17007 : REGISTER_TIMEZONE_CLASS_CONST_STRING("ALL_WITH_BC", PHP_DATE_TIMEZONE_GROUP_ALL_W_BC);
2085 17007 : REGISTER_TIMEZONE_CLASS_CONST_STRING("PER_COUNTRY", PHP_DATE_TIMEZONE_PER_COUNTRY);
2086 :
2087 17007 : INIT_CLASS_ENTRY(ce_interval, "DateInterval", date_funcs_interval);
2088 17007 : ce_interval.create_object = date_object_new_interval;
2089 17007 : date_ce_interval = zend_register_internal_class_ex(&ce_interval, NULL, NULL TSRMLS_CC);
2090 17007 : memcpy(&date_object_handlers_interval, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2091 17007 : date_object_handlers_interval.clone_obj = date_object_clone_interval;
2092 17007 : date_object_handlers_interval.read_property = date_interval_read_property;
2093 17007 : date_object_handlers_interval.write_property = date_interval_write_property;
2094 17007 : date_object_handlers_interval.get_properties = date_object_get_properties_interval;
2095 :
2096 17007 : INIT_CLASS_ENTRY(ce_period, "DatePeriod", date_funcs_period);
2097 17007 : ce_period.create_object = date_object_new_period;
2098 17007 : date_ce_period = zend_register_internal_class_ex(&ce_period, NULL, NULL TSRMLS_CC);
2099 17007 : date_ce_period->get_iterator = date_object_period_get_iterator;
2100 17007 : date_ce_period->iterator_funcs.funcs = &date_period_it_funcs;
2101 17007 : zend_class_implements(date_ce_period TSRMLS_CC, 1, zend_ce_traversable);
2102 17007 : memcpy(&date_object_handlers_period, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2103 17007 : date_object_handlers_period.clone_obj = date_object_clone_period;
2104 :
2105 : #define REGISTER_PERIOD_CLASS_CONST_STRING(const_name, value) \
2106 : zend_declare_class_constant_long(date_ce_period, const_name, sizeof(const_name)-1, value TSRMLS_CC);
2107 :
2108 17007 : REGISTER_PERIOD_CLASS_CONST_STRING("EXCLUDE_START_DATE", PHP_DATE_PERIOD_EXCLUDE_START_DATE);
2109 17007 : }
2110 :
2111 : static inline zend_object_value date_object_new_date_ex(zend_class_entry *class_type, php_date_obj **ptr TSRMLS_DC)
2112 421 : {
2113 : php_date_obj *intern;
2114 : zend_object_value retval;
2115 : zval *tmp;
2116 :
2117 421 : intern = emalloc(sizeof(php_date_obj));
2118 421 : memset(intern, 0, sizeof(php_date_obj));
2119 421 : if (ptr) {
2120 7 : *ptr = intern;
2121 : }
2122 :
2123 421 : zend_object_std_init(&intern->std, class_type TSRMLS_CC);
2124 421 : zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
2125 :
2126 421 : retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) date_object_free_storage_date, NULL TSRMLS_CC);
2127 421 : retval.handlers = &date_object_handlers_date;
2128 :
2129 421 : return retval;
2130 : }
2131 :
2132 : static zend_object_value date_object_new_date(zend_class_entry *class_type TSRMLS_DC)
2133 414 : {
2134 414 : return date_object_new_date_ex(class_type, NULL TSRMLS_CC);
2135 : }
2136 :
2137 : static zend_object_value date_object_clone_date(zval *this_ptr TSRMLS_DC)
2138 7 : {
2139 7 : php_date_obj *new_obj = NULL;
2140 7 : php_date_obj *old_obj = (php_date_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
2141 7 : zend_object_value new_ov = date_object_new_date_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
2142 :
2143 7 : zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
2144 :
2145 : /* this should probably moved to a new `timelib_time *timelime_time_clone(timelib_time *)` */
2146 7 : new_obj->time = timelib_time_ctor();
2147 7 : *new_obj->time = *old_obj->time;
2148 7 : if (old_obj->time->tz_abbr) {
2149 7 : new_obj->time->tz_abbr = strdup(old_obj->time->tz_abbr);
2150 : }
2151 7 : if (old_obj->time->tz_info) {
2152 7 : new_obj->time->tz_info = old_obj->time->tz_info;
2153 : }
2154 :
2155 7 : return new_ov;
2156 : }
2157 :
2158 : static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC)
2159 12 : {
2160 12 : if (Z_TYPE_P(d1) == IS_OBJECT && Z_TYPE_P(d2) == IS_OBJECT &&
2161 : instanceof_function(Z_OBJCE_P(d1), date_ce_date TSRMLS_CC) &&
2162 : instanceof_function(Z_OBJCE_P(d2), date_ce_date TSRMLS_CC)) {
2163 12 : php_date_obj *o1 = zend_object_store_get_object(d1 TSRMLS_CC);
2164 12 : php_date_obj *o2 = zend_object_store_get_object(d2 TSRMLS_CC);
2165 :
2166 12 : if (!o1->time->sse_uptodate) {
2167 0 : timelib_update_ts(o1->time, o1->time->tz_info);
2168 : }
2169 12 : if (!o2->time->sse_uptodate) {
2170 0 : timelib_update_ts(o2->time, o2->time->tz_info);
2171 : }
2172 :
2173 12 : return (o1->time->sse == o2->time->sse) ? 0 : ((o1->time->sse < o2->time->sse) ? -1 : 1);
2174 : }
2175 :
2176 0 : return 1;
2177 : }
2178 :
2179 : static HashTable *date_object_get_properties(zval *object TSRMLS_DC)
2180 361 : {
2181 : HashTable *props;
2182 : zval *zv;
2183 : php_date_obj *dateobj;
2184 : UChar *str;
2185 : int return_len;
2186 :
2187 361 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
2188 :
2189 361 : props = dateobj->std.properties;
2190 :
2191 361 : if (!dateobj->time) {
2192 4 : return props;
2193 : }
2194 :
2195 : /* first we add the date and time in ISO format */
2196 357 : str = date_format("Y-m-d H:i:s", 12, &return_len, dateobj->time, 1, 0 TSRMLS_CC);
2197 357 : MAKE_STD_ZVAL(zv);
2198 357 : ZVAL_UNICODEL(zv, str, return_len - 1, 0);
2199 357 : zend_hash_update(props, "date", 5, &zv, sizeof(zval), NULL);
2200 :
2201 : /* then we add the timezone name (or similar) */
2202 357 : if (dateobj->time->is_localtime) {
2203 357 : MAKE_STD_ZVAL(zv);
2204 357 : ZVAL_LONG(zv, dateobj->time->zone_type);
2205 357 : zend_hash_update(props, "timezone_type", 14, &zv, sizeof(zval), NULL);
2206 :
2207 357 : MAKE_STD_ZVAL(zv);
2208 357 : switch (dateobj->time->zone_type) {
2209 : case TIMELIB_ZONETYPE_ID:
2210 332 : ZVAL_ASCII_STRING(zv, dateobj->time->tz_info->name, 1);
2211 332 : break;
2212 : case TIMELIB_ZONETYPE_OFFSET: {
2213 12 : char *tmpstr = emalloc(sizeof("UTC+05:00"));
2214 12 : timelib_sll utc_offset = dateobj->time->z;
2215 :
2216 12 : snprintf(tmpstr, sizeof("+05:00"), "%c%02d:%02d",
2217 : utc_offset > 0 ? '-' : '+',
2218 : abs(utc_offset / 60),
2219 : abs((utc_offset % 60)));
2220 :
2221 12 : ZVAL_ASCII_STRING(zv, tmpstr, ZSTR_AUTOFREE);
2222 : }
2223 12 : break;
2224 : case TIMELIB_ZONETYPE_ABBR:
2225 13 : ZVAL_ASCII_STRING(zv, dateobj->time->tz_abbr, 1);
2226 : break;
2227 : }
2228 357 : zend_hash_update(props, "timezone", 9, &zv, sizeof(zval), NULL);
2229 : }
2230 :
2231 357 : return props;
2232 : }
2233 :
2234 : static inline zend_object_value date_object_new_timezone_ex(zend_class_entry *class_type, php_timezone_obj **ptr TSRMLS_DC)
2235 143 : {
2236 : php_timezone_obj *intern;
2237 : zend_object_value retval;
2238 : zval *tmp;
2239 :
2240 143 : intern = emalloc(sizeof(php_timezone_obj));
2241 143 : memset(intern, 0, sizeof(php_timezone_obj));
2242 143 : if (ptr) {
2243 7 : *ptr = intern;
2244 : }
2245 :
2246 143 : zend_object_std_init(&intern->std, class_type TSRMLS_CC);
2247 143 : zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
2248 :
2249 143 : retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) date_object_free_storage_timezone, NULL TSRMLS_CC);
2250 143 : retval.handlers = &date_object_handlers_timezone;
2251 :
2252 143 : return retval;
2253 : }
2254 :
2255 : static zend_object_value date_object_new_timezone(zend_class_entry *class_type TSRMLS_DC)
2256 136 : {
2257 136 : return date_object_new_timezone_ex(class_type, NULL TSRMLS_CC);
2258 : }
2259 :
2260 : static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC)
2261 7 : {
2262 7 : php_timezone_obj *new_obj = NULL;
2263 7 : php_timezone_obj *old_obj = (php_timezone_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
2264 7 : zend_object_value new_ov = date_object_new_timezone_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
2265 :
2266 7 : zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
2267 7 : new_obj->type = old_obj->type;
2268 7 : new_obj->initialized = 1;
2269 7 : switch (new_obj->type) {
2270 : case TIMELIB_ZONETYPE_ID:
2271 7 : new_obj->tzi.tz = old_obj->tzi.tz;
2272 7 : break;
2273 : case TIMELIB_ZONETYPE_OFFSET:
2274 0 : new_obj->tzi.utc_offset = old_obj->tzi.utc_offset;
2275 0 : break;
2276 : case TIMELIB_ZONETYPE_ABBR:
2277 0 : new_obj->tzi.z.utc_offset = old_obj->tzi.z.utc_offset;
2278 0 : new_obj->tzi.z.dst = old_obj->tzi.z.dst;
2279 0 : new_obj->tzi.z.abbr = old_obj->tzi.z.abbr;
2280 : break;
2281 : }
2282 :
2283 7 : return new_ov;
2284 : }
2285 :
2286 : static inline zend_object_value date_object_new_interval_ex(zend_class_entry *class_type, php_interval_obj **ptr TSRMLS_DC)
2287 15 : {
2288 : php_interval_obj *intern;
2289 : zend_object_value retval;
2290 : zval *tmp;
2291 :
2292 15 : intern = emalloc(sizeof(php_interval_obj));
2293 15 : memset(intern, 0, sizeof(php_interval_obj));
2294 15 : if (ptr) {
2295 0 : *ptr = intern;
2296 : }
2297 :
2298 15 : zend_object_std_init(&intern->std, class_type TSRMLS_CC);
2299 15 : zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
2300 :
2301 15 : retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) date_object_free_storage_interval, NULL TSRMLS_CC);
2302 15 : retval.handlers = &date_object_handlers_interval;
2303 :
2304 15 : return retval;
2305 : }
2306 :
2307 : static zend_object_value date_object_new_interval(zend_class_entry *class_type TSRMLS_DC)
2308 15 : {
2309 15 : return date_object_new_interval_ex(class_type, NULL TSRMLS_CC);
2310 : }
2311 :
2312 : static zend_object_value date_object_clone_interval(zval *this_ptr TSRMLS_DC)
2313 0 : {
2314 0 : php_interval_obj *new_obj = NULL;
2315 0 : php_interval_obj *old_obj = (php_interval_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
2316 0 : zend_object_value new_ov = date_object_new_interval_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
2317 :
2318 0 : zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
2319 :
2320 : /** FIX ME ADD CLONE STUFF **/
2321 0 : return new_ov;
2322 : }
2323 :
2324 : static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC)
2325 5 : {
2326 : HashTable *props;
2327 : zval *zv;
2328 : php_interval_obj *intervalobj;
2329 :
2330 :
2331 5 : intervalobj = (php_interval_obj *) zend_object_store_get_object(object TSRMLS_CC);
2332 :
2333 5 : props = intervalobj->std.properties;
2334 :
2335 5 : if (!intervalobj->initialized) {
2336 2 : return props;
2337 : }
2338 :
2339 : #define PHP_DATE_INTERVAL_ADD_PROPERTY(n,f) \
2340 : MAKE_STD_ZVAL(zv); \
2341 : ZVAL_LONG(zv, intervalobj->diff->f); \
2342 : zend_hash_update(props, n, strlen(n) + 1, &zv, sizeof(zval), NULL);
2343 :
2344 3 : PHP_DATE_INTERVAL_ADD_PROPERTY("y", y);
2345 3 : PHP_DATE_INTERVAL_ADD_PROPERTY("m", m);
2346 3 : PHP_DATE_INTERVAL_ADD_PROPERTY("d", d);
2347 3 : PHP_DATE_INTERVAL_ADD_PROPERTY("h", h);
2348 3 : PHP_DATE_INTERVAL_ADD_PROPERTY("i", i);
2349 3 : PHP_DATE_INTERVAL_ADD_PROPERTY("s", s);
2350 3 : PHP_DATE_INTERVAL_ADD_PROPERTY("invert", invert);
2351 3 : PHP_DATE_INTERVAL_ADD_PROPERTY("days", days);
2352 :
2353 3 : return props;
2354 : }
2355 :
2356 : static inline zend_object_value date_object_new_period_ex(zend_class_entry *class_type, php_period_obj **ptr TSRMLS_DC)
2357 5 : {
2358 : php_period_obj *intern;
2359 : zend_object_value retval;
2360 : zval *tmp;
2361 :
2362 5 : intern = emalloc(sizeof(php_period_obj));
2363 5 : memset(intern, 0, sizeof(php_period_obj));
2364 5 : if (ptr) {
2365 0 : *ptr = intern;
2366 : }
2367 :
2368 5 : zend_object_std_init(&intern->std, class_type TSRMLS_CC);
2369 5 : zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
2370 :
2371 5 : retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) date_object_free_storage_period, NULL TSRMLS_CC);
2372 5 : retval.handlers = &date_object_handlers_period;
2373 :
2374 5 : return retval;
2375 : }
2376 :
2377 : static zend_object_value date_object_new_period(zend_class_entry *class_type TSRMLS_DC)
2378 5 : {
2379 5 : return date_object_new_period_ex(class_type, NULL TSRMLS_CC);
2380 : }
2381 :
2382 : static zend_object_value date_object_clone_period(zval *this_ptr TSRMLS_DC)
2383 0 : {
2384 0 : php_period_obj *new_obj = NULL;
2385 0 : php_period_obj *old_obj = (php_period_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
2386 0 : zend_object_value new_ov = date_object_new_period_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
2387 :
2388 0 : zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
2389 :
2390 : /** FIX ME ADD CLONE STUFF **/
2391 0 : return new_ov;
2392 : }
2393 :
2394 : static void date_object_free_storage_date(void *object TSRMLS_DC)
2395 421 : {
2396 421 : php_date_obj *intern = (php_date_obj *)object;
2397 :
2398 421 : if (intern->time) {
2399 379 : timelib_time_dtor(intern->time);
2400 : }
2401 :
2402 421 : zend_object_std_dtor(&intern->std TSRMLS_CC);
2403 421 : efree(object);
2404 421 : }
2405 :
2406 : static void date_object_free_storage_timezone(void *object TSRMLS_DC)
2407 143 : {
2408 143 : php_timezone_obj *intern = (php_timezone_obj *)object;
2409 :
2410 143 : if (intern->type == TIMELIB_ZONETYPE_ABBR) {
2411 2 : free(intern->tzi.z.abbr);
2412 : }
2413 143 : zend_object_std_dtor(&intern->std TSRMLS_CC);
2414 143 : efree(object);
2415 143 : }
2416 :
2417 : static void date_object_free_storage_interval(void *object TSRMLS_DC)
2418 15 : {
2419 15 : php_interval_obj *intern = (php_interval_obj *)object;
2420 :
2421 15 : timelib_rel_time_dtor(intern->diff);
2422 15 : zend_object_std_dtor(&intern->std TSRMLS_CC);
2423 15 : efree(object);
2424 15 : }
2425 :
2426 : static void date_object_free_storage_period(void *object TSRMLS_DC)
2427 5 : {
2428 5 : php_period_obj *intern = (php_period_obj *)object;
2429 :
2430 5 : if (intern->start) {
2431 3 : timelib_time_dtor(intern->start);
2432 : }
2433 :
2434 5 : if (intern->end) {
2435 2 : timelib_time_dtor(intern->end);
2436 : }
2437 :
2438 5 : timelib_rel_time_dtor(intern->interval);
2439 5 : zend_object_std_dtor(&intern->std TSRMLS_CC);
2440 5 : efree(object);
2441 5 : }
2442 :
2443 : /* Advanced Interface */
2444 : static zval * date_instantiate(zend_class_entry *pce, zval *object TSRMLS_DC)
2445 292 : {
2446 292 : Z_TYPE_P(object) = IS_OBJECT;
2447 292 : object_init_ex(object, pce);
2448 292 : Z_SET_REFCOUNT_P(object, 1);
2449 292 : Z_UNSET_ISREF_P(object);
2450 292 : return object;
2451 : }
2452 :
2453 : /* Helper function used to store the latest found warnings and errors while
2454 : * parsing, from either strtotime or parse_from_format. */
2455 : static void update_errors_warnings(timelib_error_container *last_errors TSRMLS_DC)
2456 404 : {
2457 404 : if (DATEG(last_errors)) {
2458 288 : timelib_error_container_dtor(DATEG(last_errors));
2459 288 : DATEG(last_errors) = NULL;
2460 : }
2461 404 : DATEG(last_errors) = last_errors;
2462 404 : }
2463 :
2464 : static int date_initialize(php_date_obj *dateobj, /*const*/ char *time_str, int time_str_len, char *format, zval *timezone_object, int ctor TSRMLS_DC)
2465 325 : {
2466 : timelib_time *now;
2467 : timelib_tzinfo *tzi;
2468 325 : timelib_error_container *err = NULL;
2469 325 : int type = TIMELIB_ZONETYPE_ID, new_dst;
2470 : char *new_abbr;
2471 : timelib_sll new_offset;
2472 :
2473 325 : if (dateobj->time) {
2474 0 : timelib_time_dtor(dateobj->time);
2475 : }
2476 325 : if (format) {
2477 15 : dateobj->time = timelib_parse_from_format(format, time_str_len ? time_str : "", time_str_len ? time_str_len : 0, &err, DATE_TIMEZONEDB);
2478 : } else {
2479 310 : dateobj->time = timelib_strtotime(time_str_len ? time_str : "now", time_str_len ? time_str_len : sizeof("now") -1, &err, DATE_TIMEZONEDB);
2480 : }
2481 :
2482 : /* update last errors and warnings */
2483 325 : update_errors_warnings(err TSRMLS_CC);
2484 :
2485 :
2486 325 : if (ctor && err && err->error_count) {
2487 : /* spit out the first library error message, at least */
2488 25 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse time string (%s) at position %d (%c): %s", time_str,
2489 : err->error_messages[0].position, err->error_messages[0].character, err->error_messages[0].message);
2490 : }
2491 325 : if (err && err->error_count) {
2492 52 : return 0;
2493 : }
2494 :
2495 273 : if (timezone_object) {
2496 : php_timezone_obj *tzobj;
2497 :
2498 35 : tzobj = (php_timezone_obj *) zend_object_store_get_object(timezone_object TSRMLS_CC);
2499 35 : switch (tzobj->type) {
2500 : case TIMELIB_ZONETYPE_ID:
2501 35 : tzi = tzobj->tzi.tz;
2502 35 : break;
2503 : case TIMELIB_ZONETYPE_OFFSET:
2504 0 : new_offset = tzobj->tzi.utc_offset;
2505 0 : break;
2506 : case TIMELIB_ZONETYPE_ABBR:
2507 0 : new_offset = tzobj->tzi.z.utc_offset;
2508 0 : new_dst = tzobj->tzi.z.dst;
2509 0 : new_abbr = strdup(tzobj->tzi.z.abbr);
2510 : break;
2511 : }
2512 35 : type = tzobj->type;
2513 238 : } else if (dateobj->time->tz_info) {
2514 8 : tzi = dateobj->time->tz_info;
2515 : } else {
2516 230 : tzi = get_timezone_info(TSRMLS_C);
2517 : }
2518 :
2519 273 : now = timelib_time_ctor();
2520 273 : now->zone_type = type;
2521 273 : switch (type) {
2522 : case TIMELIB_ZONETYPE_ID:
2523 273 : now->tz_info = tzi;
2524 273 : break;
2525 : case TIMELIB_ZONETYPE_OFFSET:
2526 0 : now->z = new_offset;
2527 0 : break;
2528 : case TIMELIB_ZONETYPE_ABBR:
2529 0 : now->z = new_offset;
2530 0 : now->dst = new_dst;
2531 0 : now->tz_abbr = new_abbr;
2532 : break;
2533 : }
2534 273 : timelib_unixtime2local(now, (timelib_sll) time(NULL));
2535 :
2536 273 : timelib_fill_holes(dateobj->time, now, TIMELIB_NO_CLONE);
2537 273 : timelib_update_ts(dateobj->time, tzi);
2538 :
2539 273 : dateobj->time->have_relative = 0;
2540 :
2541 273 : timelib_time_dtor(now);
2542 :
2543 273 : return 1;
2544 : }
2545 :
2546 : /* {{{ proto DateTime date_create([string time[, DateTimeZone object]]) U
2547 : Returns new DateTime object
2548 : */
2549 : PHP_FUNCTION(date_create)
2550 210 : {
2551 210 : zval *timezone_object = NULL;
2552 210 : char *time_str = NULL;
2553 210 : int time_str_len = 0;
2554 :
2555 210 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sO", &time_str, &time_str_len, &timezone_object, date_ce_timezone) == FAILURE) {
2556 42 : RETURN_FALSE;
2557 : }
2558 :
2559 168 : date_instantiate(date_ce_date, return_value TSRMLS_CC);
2560 168 : if (!date_initialize(zend_object_store_get_object(return_value TSRMLS_CC), time_str, time_str_len, NULL, timezone_object, 0 TSRMLS_CC)) {
2561 25 : RETURN_FALSE;
2562 : }
2563 : }
2564 : /* }}} */
2565 :
2566 : /* {{{ proto DateTime date_create_from_format(string format, string time[, DateTimeZone object])
2567 : Returns new DateTime object formatted according to the specified format
2568 : */
2569 : PHP_FUNCTION(date_create_from_format)
2570 16 : {
2571 16 : zval *timezone_object = NULL;
2572 16 : char *time_str = NULL, *format_str = NULL;
2573 16 : int time_str_len = 0, format_str_len = 0;
2574 :
2575 16 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|O", &format_str, &format_str_len, &time_str, &time_str_len, &timezone_object, date_ce_timezone) == FAILURE) {
2576 1 : RETURN_FALSE;
2577 : }
2578 :
2579 15 : date_instantiate(date_ce_date, return_value TSRMLS_CC);
2580 15 : if (!date_initialize(zend_object_store_get_object(return_value TSRMLS_CC), time_str, time_str_len, format_str, timezone_object, 0 TSRMLS_CC)) {
2581 2 : RETURN_FALSE;
2582 : }
2583 : }
2584 : /* }}} */
2585 :
2586 : /* {{{ proto DateTime::__construct([string time[, DateTimeZone object]])
2587 : Creates new DateTime object
2588 : */
2589 : PHP_METHOD(DateTime, __construct)
2590 181 : {
2591 181 : zval *timezone_object = NULL;
2592 181 : char *time_str = NULL;
2593 181 : int time_str_len = 0;
2594 : zend_error_handling error_handling;
2595 :
2596 181 : zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
2597 181 : if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sO", &time_str, &time_str_len, &timezone_object, date_ce_timezone)) {
2598 140 : date_initialize(zend_object_store_get_object(getThis() TSRMLS_CC), time_str, time_str_len, NULL, timezone_object, 1 TSRMLS_CC);
2599 : }
2600 181 : zend_restore_error_handling(&error_handling TSRMLS_CC);
2601 181 : }
2602 : /* }}} */
2603 :
2604 : static int php_date_initialize_from_hash(zval **return_value, php_date_obj **dateobj, HashTable *myht TSRMLS_DC)
2605 2 : {
2606 2 : zval **z_date = NULL;
2607 2 : zval **z_timezone = NULL;
2608 2 : zval **z_timezone_type = NULL;
2609 2 : zval *tmp_obj = NULL;
2610 : timelib_tzinfo *tzi;
2611 : php_timezone_obj *tzobj;
2612 :
2613 2 : if (zend_hash_find(myht, "date", 5, (void**) &z_date) == SUCCESS) {
2614 2 : convert_to_string(*z_date);
2615 2 : if (zend_hash_find(myht, "timezone_type", 14, (void**) &z_timezone_type) == SUCCESS) {
2616 2 : convert_to_long(*z_timezone_type);
2617 2 : if (zend_hash_find(myht, "timezone", 9, (void**) &z_timezone) == SUCCESS) {
2618 2 : convert_to_string(*z_timezone);
2619 :
2620 2 : switch (Z_LVAL_PP(z_timezone_type)) {
2621 : case TIMELIB_ZONETYPE_OFFSET:
2622 : case TIMELIB_ZONETYPE_ABBR: {
2623 0 : char *tmp = emalloc(Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 2);
2624 0 : snprintf(tmp, Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 2, "%s %s", Z_STRVAL_PP(z_date), Z_STRVAL_PP(z_timezone));
2625 0 : date_initialize(*dateobj, tmp, Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 1, NULL, NULL, 0 TSRMLS_CC);
2626 0 : efree(tmp);
2627 0 : return 1;
2628 : }
2629 :
2630 : case TIMELIB_ZONETYPE_ID:
2631 2 : convert_to_string(*z_timezone);
2632 :
2633 2 : tzi = php_date_parse_tzfile(Z_STRVAL_PP(z_timezone), DATE_TIMEZONEDB TSRMLS_CC);
2634 :
2635 2 : ALLOC_INIT_ZVAL(tmp_obj);
2636 2 : tzobj = zend_object_store_get_object(tmp_obj = date_instantiate(date_ce_timezone, tmp_obj TSRMLS_CC) TSRMLS_CC);
2637 2 : tzobj->type = TIMELIB_ZONETYPE_ID;
2638 2 : tzobj->tzi.tz = tzi;
2639 2 : tzobj->initialized = 1;
2640 :
2641 2 : date_initialize(*dateobj, Z_STRVAL_PP(z_date), Z_STRLEN_PP(z_date), NULL, tmp_obj, 0 TSRMLS_CC);
2642 2 : zval_ptr_dtor(&tmp_obj);
2643 2 : return 1;
2644 : }
2645 : }
2646 : }
2647 : }
2648 0 : return 0;
2649 : }
2650 :
2651 : /* {{{ proto DateTime::__set_state()
2652 : */
2653 : PHP_METHOD(DateTime, __set_state)
2654 0 : {
2655 : php_date_obj *dateobj;
2656 : zval *array;
2657 : HashTable *myht;
2658 :
2659 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
2660 0 : RETURN_FALSE;
2661 : }
2662 :
2663 0 : myht = HASH_OF(array);
2664 :
2665 0 : date_instantiate(date_ce_date, return_value TSRMLS_CC);
2666 0 : dateobj = (php_date_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
2667 0 : php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC);
2668 : }
2669 : /* }}} */
2670 :
2671 : /* {{{ proto DateTime::__wakeup()
2672 : */
2673 : PHP_METHOD(DateTime, __wakeup)
2674 2 : {
2675 2 : zval *object = getThis();
2676 : php_date_obj *dateobj;
2677 : HashTable *myht;
2678 :
2679 2 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
2680 :
2681 2 : myht = Z_OBJPROP_P(object);
2682 :
2683 2 : php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC);
2684 2 : }
2685 : /* }}} */
2686 :
2687 : /* Helper function used to add an associative array of warnings and errors to a zval */
2688 : static void zval_from_error_container(zval *z, timelib_error_container *error)
2689 50 : {
2690 : int i;
2691 : zval *element;
2692 :
2693 50 : add_ascii_assoc_long(z, "warning_count", error->warning_count);
2694 50 : MAKE_STD_ZVAL(element);
2695 50 : array_init(element);
2696 61 : for (i = 0; i < error->warning_count; i++) {
2697 11 : add_index_ascii_string(element, error->warning_messages[i].position, error->warning_messages[i].message, 1);
2698 : }
2699 50 : add_ascii_assoc_zval(z, "warnings", element);
2700 :
2701 50 : add_ascii_assoc_long(z, "error_count", error->error_count);
2702 50 : MAKE_STD_ZVAL(element);
2703 50 : array_init(element);
2704 94 : for (i = 0; i < error->error_count; i++) {
2705 44 : add_index_ascii_string(element, error->error_messages[i].position, error->error_messages[i].message, 1);
2706 : }
2707 50 : add_ascii_assoc_zval(z, "errors", element);
2708 50 : }
2709 :
2710 : /* {{{ proto array date_get_last_errors() U
2711 : Returns the warnings and errors found while parsing a date/time string.
2712 : */
2713 : PHP_FUNCTION(date_get_last_errors)
2714 3 : {
2715 3 : if (DATEG(last_errors)) {
2716 2 : array_init(return_value);
2717 2 : zval_from_error_container(return_value, DATEG(last_errors));
2718 : } else {
2719 1 : RETURN_FALSE;
2720 : }
2721 : }
2722 : /* }}} */
2723 :
2724 : void php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAMETERS, timelib_time *parsed_time, struct timelib_error_container *error)
2725 48 : {
2726 : zval *element;
2727 :
2728 48 : array_init(return_value);
2729 : #define PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(name, elem) \
2730 : if (parsed_time->elem == -99999) { \
2731 : add_ascii_assoc_bool(return_value, #name, 0); \
2732 : } else { \
2733 : add_ascii_assoc_long(return_value, #name, parsed_time->elem); \
2734 : }
2735 48 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(year, y);
2736 48 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(month, m);
2737 48 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(day, d);
2738 48 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(hour, h);
2739 48 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(minute, i);
2740 48 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(second, s);
2741 :
2742 48 : if (parsed_time->f == -99999) {
2743 38 : add_ascii_assoc_bool(return_value, "fraction", 0);
2744 : } else {
2745 10 : add_ascii_assoc_double(return_value, "fraction", parsed_time->f);
2746 : }
2747 :
2748 48 : zval_from_error_container(return_value, error);
2749 :
2750 48 : timelib_error_container_dtor(error);
2751 :
2752 48 : add_ascii_assoc_bool(return_value, "is_localtime", parsed_time->is_localtime);
2753 :
2754 48 : if (parsed_time->is_localtime) {
2755 19 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone_type, zone_type);
2756 19 : switch (parsed_time->zone_type) {
2757 : case TIMELIB_ZONETYPE_OFFSET:
2758 5 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone, z);
2759 5 : add_ascii_assoc_bool(return_value, "is_dst", parsed_time->dst);
2760 5 : break;
2761 : case TIMELIB_ZONETYPE_ID:
2762 0 : if (parsed_time->tz_abbr) {
2763 0 : add_ascii_assoc_ascii_string(return_value, "tz_abbr", parsed_time->tz_abbr, 1);
2764 : }
2765 0 : if (parsed_time->tz_info) {
2766 0 : add_ascii_assoc_ascii_string(return_value, "tz_id", parsed_time->tz_info->name, 1);
2767 : }
2768 0 : break;
2769 : case TIMELIB_ZONETYPE_ABBR:
2770 7 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone, z);
2771 7 : add_ascii_assoc_bool(return_value, "is_dst", parsed_time->dst);
2772 7 : add_ascii_assoc_ascii_string(return_value, "tz_abbr", parsed_time->tz_abbr, 1);
2773 : break;
2774 : }
2775 : }
2776 48 : if (parsed_time->have_relative) {
2777 0 : MAKE_STD_ZVAL(element);
2778 0 : array_init(element);
2779 0 : add_ascii_assoc_long(element, "year", parsed_time->relative.y);
2780 0 : add_ascii_assoc_long(element, "month", parsed_time->relative.m);
2781 0 : add_ascii_assoc_long(element, "day", parsed_time->relative.d);
2782 0 : add_ascii_assoc_long(element, "hour", parsed_time->relative.h);
2783 0 : add_ascii_assoc_long(element, "minute", parsed_time->relative.i);
2784 0 : add_ascii_assoc_long(element, "second", parsed_time->relative.s);
2785 0 : if (parsed_time->relative.have_weekday_relative) {
2786 0 : add_ascii_assoc_long(element, "weekday", parsed_time->relative.weekday);
2787 : }
2788 0 : if (parsed_time->relative.have_special_relative && (parsed_time->relative.special.type == TIMELIB_SPECIAL_WEEKDAY)) {
2789 0 : add_ascii_assoc_long(element, "weekdays", parsed_time->relative.special.amount);
2790 : }
2791 0 : if (parsed_time->relative.first_last_day_of) {
2792 0 : add_ascii_assoc_bool(element, parsed_time->relative.first_last_day_of == 1 ? "first_day_of_month" : "last_day_of_month", 1);
2793 : }
2794 0 : add_ascii_assoc_zval(return_value, "relative", element);
2795 : }
2796 48 : timelib_time_dtor(parsed_time);
2797 48 : }
2798 :
2799 : /* {{{ proto array date_parse(string date) U
2800 : Returns associative array with detailed info about given date
2801 : */
2802 : PHP_FUNCTION(date_parse)
2803 55 : {
2804 : char *date;
2805 : int date_len;
2806 : struct timelib_error_container *error;
2807 : timelib_time *parsed_time;
2808 :
2809 55 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &date, &date_len) == FAILURE) {
2810 9 : RETURN_FALSE;
2811 : }
2812 :
2813 46 : parsed_time = timelib_strtotime(date, date_len, &error, DATE_TIMEZONEDB);
2814 46 : php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAM_PASSTHRU, parsed_time, error);
2815 : }
2816 : /* }}} */
2817 :
2818 : /* {{{ proto array date_parse_from_format(string format, string date) U
2819 : Returns associative array with detailed info about given date
2820 : */
2821 : PHP_FUNCTION(date_parse_from_format)
2822 3 : {
2823 : char *date, *format;
2824 : int date_len, format_len;
2825 : struct timelib_error_container *error;
2826 : timelib_time *parsed_time;
2827 :
2828 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &format, &format_len, &date, &date_len) == FAILURE) {
2829 1 : RETURN_FALSE;
2830 : }
2831 :
2832 2 : parsed_time = timelib_parse_from_format(format, date, date_len, &error, DATE_TIMEZONEDB);
2833 2 : php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAM_PASSTHRU, parsed_time, error);
2834 : }
2835 : /* }}} */
2836 :
2837 : /* {{{ proto string date_format(DateTime object, string format) U
2838 : Returns date formatted according to given format
2839 : */
2840 : PHP_FUNCTION(date_format)
2841 358 : {
2842 : zval *object;
2843 : php_date_obj *dateobj;
2844 : char *format;
2845 : UChar *str;
2846 : int format_len, length;
2847 :
2848 358 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_date, &format, &format_len) == FAILURE) {
2849 48 : RETURN_FALSE;
2850 : }
2851 310 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
2852 310 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
2853 309 : str = date_format(format, format_len, &length, dateobj->time, dateobj->time->is_localtime, 0 TSRMLS_CC);
2854 309 : RETURN_UNICODEL(str, length, 0);
2855 : }
2856 : /* }}} */
2857 :
2858 : /* {{{ proto string date_format_locale(DateTime object, string format) U
2859 : */
2860 : PHP_FUNCTION(date_format_locale)
2861 0 : {
2862 : zval *object;
2863 : php_date_obj *dateobj;
2864 : char *format;
2865 : UChar *str;
2866 : int format_len, length;
2867 :
2868 0 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_date, &format, &format_len) == FAILURE) {
2869 0 : RETURN_FALSE;
2870 : }
2871 0 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
2872 :
2873 0 : str = date_format(format, format_len, &length, dateobj->time, dateobj->time->is_localtime, 1 TSRMLS_CC);
2874 0 : RETURN_UNICODEL(str, length, 0);
2875 : }
2876 : /* }}} */
2877 :
2878 : /* {{{ proto DateTime date_modify(DateTime object, string modify) U
2879 : Alters the timestamp.
2880 : */
2881 : PHP_FUNCTION(date_modify)
2882 127 : {
2883 : zval *object;
2884 : php_date_obj *dateobj;
2885 : char *modify;
2886 : int modify_len;
2887 : timelib_time *tmp_time;
2888 : struct timelib_error_container *error;
2889 :
2890 127 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_date, &modify, &modify_len) == FAILURE) {
2891 48 : RETURN_FALSE;
2892 : }
2893 79 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
2894 79 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
2895 :
2896 79 : tmp_time = timelib_strtotime(modify, modify_len, &error, DATE_TIMEZONEDB);
2897 :
2898 : /* update last errors and warnings, and display the first one */
2899 79 : update_errors_warnings(error TSRMLS_CC);
2900 79 : if (error && error->error_count > 0) {
2901 43 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse time string (%s) at position %d (%c): %s", modify,
2902 : error->error_messages[0].position, error->error_messages[0].character, error->error_messages[0].message);
2903 43 : timelib_time_dtor(tmp_time);
2904 43 : RETURN_FALSE;
2905 : }
2906 :
2907 36 : memcpy(&dateobj->time->relative, &tmp_time->relative, sizeof(struct timelib_rel_time));
2908 36 : dateobj->time->have_relative = tmp_time->have_relative;
2909 36 : dateobj->time->sse_uptodate = 0;
2910 36 : timelib_time_dtor(tmp_time);
2911 :
2912 36 : timelib_update_ts(dateobj->time, NULL);
2913 36 : timelib_update_from_sse(dateobj->time);
2914 36 : dateobj->time->have_relative = 0;
2915 :
2916 36 : RETURN_ZVAL(object, 1, 0);
2917 : }
2918 : /* }}} */
2919 :
2920 : /* {{{ proto DateTime date_add(DateTime object, DateInterval interval) U
2921 : Adds an interval to the current date in object.
2922 : */
2923 : PHP_FUNCTION(date_add)
2924 5 : {
2925 : zval *object, *interval;
2926 : php_date_obj *dateobj;
2927 : php_interval_obj *intobj;
2928 5 : int bias = 1;
2929 :
2930 5 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) {
2931 1 : RETURN_FALSE;
2932 : }
2933 4 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
2934 4 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
2935 4 : intobj = (php_interval_obj *) zend_object_store_get_object(interval TSRMLS_CC);
2936 4 : DATE_CHECK_INITIALIZED(intobj->initialized, DateInterval);
2937 :
2938 :
2939 4 : if (intobj->diff->have_weekday_relative || intobj->diff->have_special_relative) {
2940 0 : memcpy(&dateobj->time->relative, intobj->diff, sizeof(struct timelib_rel_time));
2941 : } else {
2942 4 : if (intobj->diff->invert) {
2943 0 : bias = -1;
2944 : }
2945 4 : dateobj->time->relative.y = intobj->diff->y * bias;
2946 4 : dateobj->time->relative.m = intobj->diff->m * bias;
2947 4 : dateobj->time->relative.d = intobj->diff->d * bias;
2948 4 : dateobj->time->relative.h = intobj->diff->h * bias;
2949 4 : dateobj->time->relative.i = intobj->diff->i * bias;
2950 4 : dateobj->time->relative.s = intobj->diff->s * bias;
2951 4 : dateobj->time->relative.weekday = 0;
2952 4 : dateobj->time->relative.have_weekday_relative = 0;
2953 : }
2954 4 : dateobj->time->have_relative = 1;
2955 4 : dateobj->time->sse_uptodate = 0;
2956 :
2957 4 : timelib_update_ts(dateobj->time, NULL);
2958 4 : timelib_update_from_sse(dateobj->time);
2959 4 : dateobj->time->have_relative = 0;
2960 :
2961 4 : RETURN_ZVAL(object, 1, 0);
2962 : }
2963 : /* }}} */
2964 :
2965 : /* {{{ proto DateTime date_sub(DateTime object, DateInterval interval) U
2966 : Subtracts an interval to the current date in object.
2967 : */
2968 : PHP_FUNCTION(date_sub)
2969 4 : {
2970 : zval *object, *interval;
2971 : php_date_obj *dateobj;
2972 : php_interval_obj *intobj;
2973 4 : int bias = 1;
2974 :
2975 4 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) {
2976 0 : RETURN_FALSE;
2977 : }
2978 4 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
2979 4 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
2980 4 : intobj = (php_interval_obj *) zend_object_store_get_object(interval TSRMLS_CC);
2981 4 : DATE_CHECK_INITIALIZED(intobj->initialized, DateInterval);
2982 :
2983 4 : if (intobj->diff->invert) {
2984 0 : bias = -1;
2985 : }
2986 :
2987 4 : dateobj->time->relative.y = 0 - (intobj->diff->y * bias);
2988 4 : dateobj->time->relative.m = 0 - (intobj->diff->m * bias);
2989 4 : dateobj->time->relative.d = 0 - (intobj->diff->d * bias);
2990 4 : dateobj->time->relative.h = 0 - (intobj->diff->h * bias);
2991 4 : dateobj->time->relative.i = 0 - (intobj->diff->i * bias);
2992 4 : dateobj->time->relative.s = 0 - (intobj->diff->s * bias);
2993 4 : dateobj->time->have_relative = 1;
2994 4 : dateobj->time->relative.weekday = 0;
2995 4 : dateobj->time->relative.have_weekday_relative = 0;
2996 4 : dateobj->time->sse_uptodate = 0;
2997 :
2998 4 : timelib_update_ts(dateobj->time, NULL);
2999 4 : timelib_update_from_sse(dateobj->time);
3000 :
3001 4 : RETURN_ZVAL(object, 1, 0);
3002 : }
3003 : /* }}} */
3004 :
3005 : /* {{{ proto DateTimeZone date_timezone_get(DateTime object) U
3006 : Return new DateTimeZone object relative to give DateTime
3007 : */
3008 : PHP_FUNCTION(date_timezone_get)
3009 68 : {
3010 : zval *object;
3011 : php_date_obj *dateobj;
3012 : php_timezone_obj *tzobj;
3013 :
3014 68 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_date) == FAILURE) {
3015 33 : RETURN_FALSE;
3016 : }
3017 35 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
3018 35 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
3019 35 : if (dateobj->time->is_localtime/* && dateobj->time->tz_info*/) {
3020 35 : date_instantiate(date_ce_timezone, return_value TSRMLS_CC);
3021 35 : tzobj = (php_timezone_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
3022 35 : tzobj->initialized = 1;
3023 35 : tzobj->type = dateobj->time->zone_type;
3024 35 : switch (dateobj->time->zone_type) {
3025 : case TIMELIB_ZONETYPE_ID:
3026 23 : tzobj->tzi.tz = dateobj->time->tz_info;
3027 23 : break;
3028 : case TIMELIB_ZONETYPE_OFFSET:
3029 10 : tzobj->tzi.utc_offset = dateobj->time->z;
3030 10 : break;
3031 : case TIMELIB_ZONETYPE_ABBR:
3032 2 : tzobj->tzi.z.utc_offset = dateobj->time->z;
3033 2 : tzobj->tzi.z.dst = dateobj->time->dst;
3034 2 : tzobj->tzi.z.abbr = strdup(dateobj->time->tz_abbr);
3035 : break;
3036 : }
3037 : } else {
3038 0 : RETURN_FALSE;
3039 : }
3040 : }
3041 : /* }}} */
3042 :
3043 : /* {{{ proto DateTimeZone date_timezone_set(DateTime object, DateTimeZone object) U
3044 : Sets the timezone for the DateTime object.
3045 : */
3046 : PHP_FUNCTION(date_timezone_set)
3047 104 : {
3048 : zval *object;
3049 : zval *timezone_object;
3050 : php_date_obj *dateobj;
3051 : php_timezone_obj *tzobj;
3052 :
3053 104 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &timezone_object, date_ce_timezone) == FAILURE) {
3054 92 : RETURN_FALSE;
3055 : }
3056 12 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
3057 12 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
3058 12 : tzobj = (php_timezone_obj *) zend_object_store_get_object(timezone_object TSRMLS_CC);
3059 12 : if (tzobj->type != TIMELIB_ZONETYPE_ID) {
3060 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can only do this for zones with ID for now");
3061 0 : return;
3062 : }
3063 12 : timelib_set_timezone(dateobj->time, tzobj->tzi.tz);
3064 12 : timelib_unixtime2local(dateobj->time, dateobj->time->sse);
3065 :
3066 12 : RETURN_ZVAL(object, 1, 0);
3067 : }
3068 : /* }}} */
3069 :
3070 : /* {{{ proto long date_offset_get(DateTime object) U
3071 : Returns the DST offset.
3072 : */
3073 : PHP_FUNCTION(date_offset_get)
3074 38 : {
3075 : zval *object;
3076 : php_date_obj *dateobj;
3077 : timelib_time_offset *offset;
3078 :
3079 38 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_date) == FAILURE) {
3080 34 : RETURN_FALSE;
3081 : }
3082 4 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
3083 4 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
3084 4 : if (dateobj->time->is_localtime/* && dateobj->time->tz_info*/) {
3085 4 : switch (dateobj->time->zone_type) {
3086 : case TIMELIB_ZONETYPE_ID:
3087 4 : offset = timelib_get_time_zone_info(dateobj->time->sse, dateobj->time->tz_info);
3088 4 : RETVAL_LONG(offset->offset);
3089 4 : timelib_time_offset_dtor(offset);
3090 4 : break;
3091 : case TIMELIB_ZONETYPE_OFFSET:
3092 0 : RETVAL_LONG(dateobj->time->z * -60);
3093 0 : break;
3094 : case TIMELIB_ZONETYPE_ABBR:
3095 0 : RETVAL_LONG((dateobj->time->z - (60 * dateobj->time->dst)) * -60);
3096 : break;
3097 : }
3098 4 : return;
3099 : } else {
3100 0 : RETURN_LONG(0);
3101 : }
3102 : }
3103 : /* }}} */
3104 :
3105 : /* {{{ proto DateTime date_time_set(DateTime object, long hour, long minute[, long second]) U
3106 : Sets the time.
3107 : */
3108 : PHP_FUNCTION(date_time_set)
3109 223 : {
3110 : zval *object;
3111 : php_date_obj *dateobj;
3112 223 : long h, i, s = 0;
3113 :
3114 223 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_date, &h, &i, &s) == FAILURE) {
3115 116 : RETURN_FALSE;
3116 : }
3117 107 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
3118 107 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
3119 107 : dateobj->time->h = h;
3120 107 : dateobj->time->i = i;
3121 107 : dateobj->time->s = s;
3122 107 : timelib_update_ts(dateobj->time, NULL);
3123 :
3124 107 : RETURN_ZVAL(object, 1, 0);
3125 : }
3126 : /* }}} */
3127 :
3128 : /* {{{ proto DateTime date_date_set(DateTime object, long year, long month, long day) U
3129 : Sets the date.
3130 : */
3131 : PHP_FUNCTION(date_date_set)
3132 214 : {
3133 : zval *object;
3134 : php_date_obj *dateobj;
3135 : long y, m, d;
3136 :
3137 214 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Olll", &object, date_ce_date, &y, &m, &d) == FAILURE) {
3138 117 : RETURN_FALSE;
3139 : }
3140 97 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
3141 97 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
3142 97 : dateobj->time->y = y;
3143 97 : dateobj->time->m = m;
3144 97 : dateobj->time->d = d;
3145 97 : timelib_update_ts(dateobj->time, NULL);
3146 :
3147 97 : RETURN_ZVAL(object, 1, 0);
3148 : }
3149 : /* }}} */
3150 :
3151 : /* {{{ proto DateTime date_isodate_set(DateTime object, long year, long week[, long day]) U
3152 : Sets the ISO date.
3153 : */
3154 : PHP_FUNCTION(date_isodate_set)
3155 216 : {
3156 : zval *object;
3157 : php_date_obj *dateobj;
3158 216 : long y, w, d = 1;
3159 :
3160 216 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_date, &y, &w, &d) == FAILURE) {
3161 117 : RETURN_FALSE;
3162 : }
3163 99 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
3164 99 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
3165 99 : dateobj->time->y = y;
3166 99 : dateobj->time->m = 1;
3167 99 : dateobj->time->d = 1;
3168 99 : dateobj->time->relative.d = timelib_daynr_from_weeknr(y, w, d);
3169 99 : dateobj->time->have_relative = 1;
3170 :
3171 99 : timelib_update_ts(dateobj->time, NULL);
3172 :
3173 99 : RETURN_ZVAL(object, 1, 0);
3174 : }
3175 : /* }}} */
3176 :
3177 : /* {{{ proto DateTime date_timestamp_set(DateTime object, long unixTimestamp) U
3178 : Sets the date and time based on an Unix timestamp.
3179 : */
3180 : PHP_FUNCTION(date_timestamp_set)
3181 1 : {
3182 : zval *object;
3183 : php_date_obj *dateobj;
3184 : long timestamp;
3185 :
3186 1 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", &object, date_ce_date, ×tamp) == FAILURE) {
3187 0 : RETURN_FALSE;
3188 : }
3189 1 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
3190 1 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
3191 1 : timelib_unixtime2local(dateobj->time, (timelib_sll)timestamp);
3192 1 : timelib_update_ts(dateobj->time, NULL);
3193 :
3194 1 : RETURN_ZVAL(object, 1, 0);
3195 : }
3196 : /* }}} */
3197 :
3198 : /* {{{ proto long date_timestamp_get(DateTime object) U
3199 : Gets the Unix timestamp.
3200 : */
3201 : PHP_FUNCTION(date_timestamp_get)
3202 2 : {
3203 : zval *object;
3204 : php_date_obj *dateobj;
3205 : long timestamp;
3206 : int error;
3207 :
3208 2 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_date) == FAILURE) {
3209 1 : RETURN_FALSE;
3210 : }
3211 1 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
3212 1 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
3213 1 : timelib_update_ts(dateobj->time, NULL);
3214 :
3215 1 : timestamp = timelib_date_to_int(dateobj->time, &error);
3216 1 : if (error) {
3217 0 : RETURN_FALSE;
3218 : } else {
3219 1 : RETVAL_LONG(timestamp);
3220 : }
3221 : }
3222 : /* }}} */
3223 :
3224 : /* {{{ proto DateInterval date_diff(DateTime object [, bool absolute]) U
3225 : Returns the difference between two DateTime objects.
3226 : */
3227 : PHP_FUNCTION(date_diff)
3228 1 : {
3229 : zval *object1, *object2;
3230 : php_date_obj *dateobj1, *dateobj2;
3231 : php_interval_obj *interval;
3232 1 : long absolute = 0;
3233 :
3234 1 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO|l", &object1, date_ce_date, &object2, date_ce_date, &absolute) == FAILURE) {
3235 0 : RETURN_FALSE;
3236 : }
3237 1 : dateobj1 = (php_date_obj *) zend_object_store_get_object(object1 TSRMLS_CC);
3238 1 : dateobj2 = (php_date_obj *) zend_object_store_get_object(object2 TSRMLS_CC);
3239 1 : DATE_CHECK_INITIALIZED(dateobj1->time, DateTime);
3240 1 : DATE_CHECK_INITIALIZED(dateobj2->time, DateTime);
3241 1 : timelib_update_ts(dateobj1->time, NULL);
3242 1 : timelib_update_ts(dateobj2->time, NULL);
3243 :
3244 1 : date_instantiate(date_ce_interval, return_value TSRMLS_CC);
3245 1 : interval = zend_object_store_get_object(return_value TSRMLS_CC);
3246 1 : interval->diff = timelib_diff(dateobj1->time, dateobj2->time);
3247 1 : if (absolute) {
3248 0 : interval->diff->invert = 0;
3249 : }
3250 1 : interval->initialized = 1;
3251 : }
3252 : /* }}} */
3253 :
3254 : static int timezone_initialize(timelib_tzinfo **tzi, /*const*/ char *tz TSRMLS_DC)
3255 112 : {
3256 : char *tzid;
3257 :
3258 112 : *tzi = NULL;
3259 :
3260 112 : if ((tzid = timelib_timezone_id_from_abbr(tz, -1, 0))) {
3261 11 : *tzi = php_date_parse_tzfile(tzid, DATE_TIMEZONEDB TSRMLS_CC);
3262 : } else {
3263 101 : *tzi = php_date_parse_tzfile(tz, DATE_TIMEZONEDB TSRMLS_CC);
3264 : }
3265 :
3266 112 : if (*tzi) {
3267 67 : return SUCCESS;
3268 : } else {
3269 45 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or bad timezone (%s)", tz);
3270 45 : return FAILURE;
3271 : }
3272 : }
3273 :
3274 : /* {{{ proto DateTimeZone timezone_open(string timezone) U
3275 : Returns new DateTimeZone object
3276 : */
3277 : PHP_FUNCTION(timezone_open)
3278 50 : {
3279 : char *tz;
3280 : int tz_len;
3281 50 : timelib_tzinfo *tzi = NULL;
3282 : php_timezone_obj *tzobj;
3283 :
3284 50 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &tz, &tz_len) == FAILURE) {
3285 8 : RETURN_FALSE;
3286 : }
3287 42 : if (SUCCESS != timezone_initialize(&tzi, tz TSRMLS_CC)) {
3288 22 : RETURN_FALSE;
3289 : }
3290 20 : tzobj = zend_object_store_get_object(date_instantiate(date_ce_timezone, return_value TSRMLS_CC) TSRMLS_CC);
3291 20 : tzobj->type = TIMELIB_ZONETYPE_ID;
3292 20 : tzobj->tzi.tz = tzi;
3293 20 : tzobj->initialized = 1;
3294 : }
3295 : /* }}} */
3296 :
3297 : /* {{{ proto DateTimeZone::__construct(string timezone)
3298 : Creates new DateTimeZone object.
3299 : */
3300 : PHP_METHOD(DateTimeZone, __construct)
3301 77 : {
3302 : char *tz;
3303 : int tz_len;
3304 77 : timelib_tzinfo *tzi = NULL;
3305 : php_timezone_obj *tzobj;
3306 : zend_error_handling error_handling;
3307 :
3308 77 : zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
3309 77 : if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &tz, &tz_len)) {
3310 70 : if (SUCCESS == timezone_initialize(&tzi, tz TSRMLS_CC)) {
3311 47 : tzobj = zend_object_store_get_object(getThis() TSRMLS_CC);
3312 47 : tzobj->type = TIMELIB_ZONETYPE_ID;
3313 47 : tzobj->tzi.tz = tzi;
3314 47 : tzobj->initialized = 1;
3315 : } else {
3316 23 : ZVAL_NULL(getThis());
3317 : }
3318 : }
3319 77 : zend_restore_error_handling(&error_handling TSRMLS_CC);
3320 77 : }
3321 : /* }}} */
3322 :
3323 : /* {{{ proto string timezone_name_get(DateTimeZone object) U
3324 : Returns the name of the timezone.
3325 : */
3326 : PHP_FUNCTION(timezone_name_get)
3327 42 : {
3328 : zval *object;
3329 : php_timezone_obj *tzobj;
3330 :
3331 42 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_timezone) == FAILURE) {
3332 6 : RETURN_FALSE;
3333 : }
3334 36 : tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
3335 36 : DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
3336 :
3337 34 : switch (tzobj->type) {
3338 : case TIMELIB_ZONETYPE_ID:
3339 29 : RETURN_ASCII_STRING(tzobj->tzi.tz->name, 1);
3340 : break;
3341 : case TIMELIB_ZONETYPE_OFFSET: {
3342 5 : char *tmpstr = emalloc(sizeof("UTC+05:00"));
3343 5 : timelib_sll utc_offset = tzobj->tzi.utc_offset;
3344 :
3345 5 : snprintf(tmpstr, sizeof("+05:00"), "%c%02d:%02d",
3346 : utc_offset > 0 ? '-' : '+',
3347 : abs(utc_offset / 60),
3348 : abs((utc_offset % 60)));
3349 :
3350 5 : RETURN_ASCII_STRING(tmpstr, ZSTR_AUTOFREE);
3351 : }
3352 : break;
3353 : case TIMELIB_ZONETYPE_ABBR:
3354 0 : RETURN_ASCII_STRING(tzobj->tzi.z.abbr, 1);
3355 : break;
3356 : }
3357 : }
3358 : /* }}} */
3359 :
3360 : /* {{{ proto string timezone_name_from_abbr(string abbr[, long gmtOffset[, long isdst]]) U
3361 : Returns the timezone name from abbrevation
3362 : */
3363 : PHP_FUNCTION(timezone_name_from_abbr)
3364 105 : {
3365 : char *abbr;
3366 : char *tzid;
3367 : int abbr_len;
3368 105 : long gmtoffset = -1;
3369 105 : long isdst = -1;
3370 :
3371 105 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ll", &abbr, &abbr_len, &gmtoffset, &isdst) == FAILURE) {
3372 35 : RETURN_FALSE;
3373 : }
3374 70 : tzid = timelib_timezone_id_from_abbr(abbr, gmtoffset, isdst);
3375 :
3376 70 : if (tzid) {
3377 66 : RETURN_ASCII_STRING(tzid, 1);
3378 : } else {
3379 4 : RETURN_FALSE;
3380 : }
3381 : }
3382 : /* }}} */
3383 :
3384 : /* {{{ proto long timezone_offset_get(DateTimeZone object, DateTime object) U
3385 : Returns the timezone offset.
3386 : */
3387 : PHP_FUNCTION(timezone_offset_get)
3388 115 : {
3389 : zval *object, *dateobject;
3390 : php_timezone_obj *tzobj;
3391 : php_date_obj *dateobj;
3392 : timelib_time_offset *offset;
3393 :
3394 115 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_timezone, &dateobject, date_ce_date) == FAILURE) {
3395 97 : RETURN_FALSE;
3396 : }
3397 18 : tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
3398 18 : DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
3399 18 : dateobj = (php_date_obj *) zend_object_store_get_object(dateobject TSRMLS_CC);
3400 18 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
3401 :
3402 18 : switch (tzobj->type) {
3403 : case TIMELIB_ZONETYPE_ID:
3404 11 : offset = timelib_get_time_zone_info(dateobj->time->sse, tzobj->tzi.tz);
3405 11 : RETVAL_LONG(offset->offset);
3406 11 : timelib_time_offset_dtor(offset);
3407 11 : break;
3408 : case TIMELIB_ZONETYPE_OFFSET:
3409 5 : RETURN_LONG(tzobj->tzi.utc_offset * -60);
3410 : break;
3411 : case TIMELIB_ZONETYPE_ABBR:
3412 2 : RETURN_LONG((tzobj->tzi.z.utc_offset - (tzobj->tzi.z.dst*60)) * -60);
3413 : break;
3414 : }
3415 : }
3416 : /* }}} */
3417 :
3418 : /* {{{ proto array timezone_transitions_get(DateTimeZone object [, long timestamp_begin [, long timestamp_end ]]) U
3419 : Returns numerically indexed array containing associative array for all transitions in the specified range for the timezone.
3420 : */
3421 : PHP_FUNCTION(timezone_transitions_get)
3422 94 : {
3423 : zval *object, *element;
3424 : php_timezone_obj *tzobj;
3425 94 : unsigned int i, begin = 0, found;
3426 94 : long timestamp_begin = LONG_MIN, timestamp_end = LONG_MAX;
3427 :
3428 94 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|ll", &object, date_ce_timezone, ×tamp_begin, ×tamp_end) == FAILURE) {
3429 60 : RETURN_FALSE;
3430 : }
3431 34 : tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
3432 34 : DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
3433 34 : if (tzobj->type != TIMELIB_ZONETYPE_ID) {
3434 0 : RETURN_FALSE;
3435 : }
3436 :
3437 : #define add_nominal() \
3438 : MAKE_STD_ZVAL(element); \
3439 : array_init(element); \
3440 : add_ascii_assoc_long(element, "ts", timestamp_begin); \
3441 : add_ascii_assoc_unicode(element, "time", (UChar*) php_format_date(DATE_FORMAT_ISO8601, 13, timestamp_begin, 0 TSRMLS_CC), 0); \
3442 : add_ascii_assoc_long(element, "offset", tzobj->tzi.tz->type[0].offset); \
3443 : add_ascii_assoc_bool(element, "isdst", tzobj->tzi.tz->type[0].isdst); \
3444 : add_ascii_assoc_ascii_string(element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[0].abbr_idx], 1); \
3445 : add_next_index_zval(return_value, element);
3446 :
3447 : #define add(i,ts) \
3448 : MAKE_STD_ZVAL(element); \
3449 : array_init(element); \
3450 : add_ascii_assoc_long(element, "ts", ts); \
3451 : add_ascii_assoc_unicode(element, "time", (UChar*) php_format_date(DATE_FORMAT_ISO8601, 13, ts, 0 TSRMLS_CC), 0); \
3452 : add_ascii_assoc_long(element, "offset", tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].offset); \
3453 : add_ascii_assoc_bool(element, "isdst", tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].isdst); \
3454 : add_ascii_assoc_ascii_string(element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].abbr_idx], 1); \
3455 : add_next_index_zval(return_value, element);
3456 :
3457 : #define add_last() add(tzobj->tzi.tz->timecnt - 1, timestamp_begin)
3458 :
3459 34 : array_init(return_value);
3460 :
3461 34 : if (timestamp_begin == LONG_MIN) {
3462 4 : add_nominal();
3463 4 : begin = 0;
3464 4 : found = 1;
3465 : } else {
3466 30 : begin = 0;
3467 30 : found = 0;
3468 30 : if (tzobj->tzi.tz->timecnt > 0) {
3469 : do {
3470 3375 : if (tzobj->tzi.tz->trans[begin] > timestamp_begin) {
3471 30 : if (begin > 0) {
3472 30 : add(begin - 1, timestamp_begin);
3473 : } else {
3474 0 : add_nominal();
3475 : }
3476 30 : found = 1;
3477 30 : break;
3478 : }
3479 3345 : begin++;
3480 3345 : } while (begin < tzobj->tzi.tz->timecnt);
3481 : }
3482 : }
3483 :
3484 34 : if (!found) {
3485 0 : if (tzobj->tzi.tz->timecnt > 0) {
3486 0 : add_last();
3487 : } else {
3488 0 : add_nominal();
3489 : }
3490 : } else {
3491 4917 : for (i = begin; i < tzobj->tzi.tz->timecnt; ++i) {
3492 4883 : if (tzobj->tzi.tz->trans[i] < timestamp_end) {
3493 1073 : add(i, tzobj->tzi.tz->trans[i]);
3494 : }
3495 : }
3496 : }
3497 : }
3498 : /* }}} */
3499 :
3500 : /* {{{ proto array timezone_location_get()
3501 : Returns location information for a timezone, including country code, latitude/longitude and comments
3502 : */
3503 : PHP_FUNCTION(timezone_location_get)
3504 1 : {
3505 : zval *object;
3506 : php_timezone_obj *tzobj;
3507 :
3508 1 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_timezone) == FAILURE) {
3509 0 : RETURN_FALSE;
3510 : }
3511 1 : tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
3512 1 : DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
3513 1 : if (tzobj->type != TIMELIB_ZONETYPE_ID) {
3514 0 : RETURN_FALSE;
3515 : }
3516 :
3517 1 : array_init(return_value);
3518 1 : add_assoc_string(return_value, "country_code", tzobj->tzi.tz->location.country_code, 1);
3519 1 : add_assoc_double(return_value, "latitude", tzobj->tzi.tz->location.latitude);
3520 1 : add_assoc_double(return_value, "longitude", tzobj->tzi.tz->location.longitude);
3521 1 : add_assoc_string(return_value, "comments", tzobj->tzi.tz->location.comments, 1);
3522 : }
3523 : /* }}} */
3524 :
3525 : static int date_interval_initialize(timelib_rel_time **rt, /*const*/ char *format, int format_length TSRMLS_DC)
3526 9 : {
3527 9 : timelib_time *b = NULL, *e = NULL;
3528 9 : timelib_rel_time *p = NULL;
3529 9 : int r = 0;
3530 9 : int retval = 0;
3531 : struct timelib_error_container *errors;
3532 :
3533 9 : timelib_strtointerval(format, format_length, &b, &e, &p, &r, &errors);
3534 :
3535 9 : if (errors->error_count > 0) {
3536 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or bad format (%s)", format);
3537 0 : retval = FAILURE;
3538 : } else {
3539 9 : *rt = p;
3540 9 : retval = SUCCESS;
3541 : }
3542 9 : timelib_error_container_dtor(errors);
3543 9 : return retval;
3544 : }
3545 :
3546 : /* {{{ date_interval_read_property */
3547 : zval *date_interval_read_property(zval *object, zval *member, int type TSRMLS_DC)
3548 2 : {
3549 : php_interval_obj *obj;
3550 : zval *retval;
3551 : zval tmp_member;
3552 2 : timelib_sll value = -1;
3553 :
3554 2 : if (member->type != IS_STRING) {
3555 2 : tmp_member = *member;
3556 2 : zval_copy_ctor(&tmp_member);
3557 2 : convert_to_string(&tmp_member);
3558 2 : member = &tmp_member;
3559 : }
3560 :
3561 2 : obj = (php_interval_obj *)zend_objects_get_address(object TSRMLS_CC);
3562 :
3563 : #define GET_VALUE_FROM_STRUCT(n,m) \
3564 : if (strcmp(Z_STRVAL_P(member), m) == 0) { \
3565 : value = obj->diff->n; \
3566 : }
3567 2 : GET_VALUE_FROM_STRUCT(y, "y");
3568 2 : GET_VALUE_FROM_STRUCT(m, "m");
3569 2 : GET_VALUE_FROM_STRUCT(d, "d");
3570 2 : GET_VALUE_FROM_STRUCT(h, "h");
3571 2 : GET_VALUE_FROM_STRUCT(i, "i");
3572 2 : GET_VALUE_FROM_STRUCT(s, "s");
3573 2 : GET_VALUE_FROM_STRUCT(invert, "invert");
3574 2 : GET_VALUE_FROM_STRUCT(days, "days");
3575 :
3576 2 : ALLOC_INIT_ZVAL(retval);
3577 2 : Z_SET_REFCOUNT_P(retval, 0);
3578 :
3579 2 : if (value == -1) {
3580 1 : php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unknown property (%s)", Z_STRVAL_P(member));
3581 : }
3582 :
3583 1 : ZVAL_LONG(retval, value);
3584 :
3585 1 : if (member == &tmp_member) {
3586 1 : zval_dtor(member);
3587 : }
3588 :
3589 1 : return retval;
3590 : }
3591 : /* }}} */
3592 :
3593 : /* {{{ date_interval_write_property */
3594 : void date_interval_write_property(zval *object, zval *member, zval *value TSRMLS_DC)
3595 1 : {
3596 : php_interval_obj *obj;
3597 : zval tmp_member, tmp_value;
3598 1 : int found = 0;
3599 :
3600 1 : if (member->type != IS_STRING) {
3601 1 : tmp_member = *member;
3602 1 : zval_copy_ctor(&tmp_member);
3603 1 : convert_to_string(&tmp_member);
3604 1 : member = &tmp_member;
3605 : }
3606 1 : obj = (php_interval_obj *)zend_objects_get_address(object TSRMLS_CC);
3607 :
3608 : #define SET_VALUE_FROM_STRUCT(n,m) \
3609 : if (strcmp(Z_STRVAL_P(member), m) == 0) { \
3610 : if (value->type != IS_LONG) { \
3611 : tmp_value = *value; \
3612 : zval_copy_ctor(&tmp_value); \
3613 : convert_to_long(&tmp_value); \
3614 : value = &tmp_value; \
3615 : } \
3616 : found = 1; \
3617 : obj->diff->n = Z_LVAL_P(value); \
3618 : if (value == &tmp_value) { \
3619 : zval_dtor(value); \
3620 : } \
3621 : }
3622 :
3623 1 : SET_VALUE_FROM_STRUCT(y, "y");
3624 1 : SET_VALUE_FROM_STRUCT(m, "m");
3625 1 : SET_VALUE_FROM_STRUCT(d, "d");
3626 1 : SET_VALUE_FROM_STRUCT(h, "h");
3627 1 : SET_VALUE_FROM_STRUCT(i, "i");
3628 1 : SET_VALUE_FROM_STRUCT(s, "s");
3629 1 : SET_VALUE_FROM_STRUCT(invert, "invert");
3630 :
3631 1 : if (!found) {
3632 0 : php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unknown property (%s)", Z_STRVAL_P(member));
3633 : }
3634 :
3635 1 : if (member == &tmp_member) {
3636 1 : zval_dtor(member);
3637 : }
3638 1 : }
3639 : /* }}} */
3640 :
3641 :
3642 : /* {{{ proto DateInterval::__construct([string interval_spec])
3643 : Creates new DateInterval object.
3644 : */
3645 : PHP_METHOD(DateInterval, __construct)
3646 9 : {
3647 9 : char *interval_string = NULL;
3648 : int interval_string_length;
3649 : php_interval_obj *diobj;
3650 : timelib_rel_time *reltime;
3651 : zend_error_handling error_handling;
3652 :
3653 9 : zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
3654 9 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &interval_string, &interval_string_length) == SUCCESS) {
3655 9 : if (date_interval_initialize(&reltime, interval_string, interval_string_length TSRMLS_CC) == SUCCESS) {
3656 9 : diobj = zend_object_store_get_object(getThis() TSRMLS_CC);
3657 9 : diobj->diff = reltime;
3658 9 : diobj->initialized = 1;
3659 : } else {
3660 0 : ZVAL_NULL(getThis());
3661 : }
3662 : }
3663 9 : zend_restore_error_handling(&error_handling TSRMLS_CC);
3664 9 : }
3665 : /* }}} */
3666 :
3667 : /* {{{ proto DateInterval date_interval_create_from_date_string(string time)
3668 : Uses the normal date parsers and sets up a DateInterval from the relative parts of the parsed string
3669 : */
3670 : PHP_FUNCTION(date_interval_create_from_date_string)
3671 4 : {
3672 4 : char *time_str = NULL;
3673 4 : int time_str_len = 0;
3674 : timelib_time *time;
3675 4 : timelib_error_container *err = NULL;
3676 : php_interval_obj *diobj;
3677 :
3678 4 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &time_str, &time_str_len) == FAILURE) {
3679 0 : RETURN_FALSE;
3680 : }
3681 :
3682 4 : date_instantiate(date_ce_interval, return_value TSRMLS_CC);
3683 :
3684 4 : time = timelib_strtotime(time_str, time_str_len, &err, DATE_TIMEZONEDB);
3685 4 : diobj = (php_interval_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
3686 4 : diobj->diff = timelib_rel_time_clone(&time->relative);
3687 4 : diobj->initialized = 1;
3688 4 : timelib_time_dtor(time);
3689 4 : timelib_error_container_dtor(err);
3690 : }
3691 : /* }}} */
3692 :
3693 : /* {{{ date_interval_format - */
3694 : static char *date_interval_format(char *format, int format_len, timelib_rel_time *t)
3695 0 : {
3696 0 : smart_str string = {0};
3697 0 : int i, length, have_format_spec = 0;
3698 : char buffer[33];
3699 :
3700 0 : if (!format_len) {
3701 0 : return estrdup("");
3702 : }
3703 :
3704 0 : for (i = 0; i < format_len; i++) {
3705 0 : if (have_format_spec) {
3706 0 : switch (format[i]) {
3707 0 : case 'Y': length = slprintf(buffer, 32, "%02d", (int) t->y); break;
3708 0 : case 'y': length = slprintf(buffer, 32, "%d", (int) t->y); break;
3709 :
3710 0 : case 'M': length = slprintf(buffer, 32, "%02d", (int) t->m); break;
3711 0 : case 'm': length = slprintf(buffer, 32, "%d", (int) t->m); break;
3712 :
3713 0 : case 'D': length = slprintf(buffer, 32, "%02d", (int) t->d); break;
3714 0 : case 'd': length = slprintf(buffer, 32, "%d", (int) t->d); break;
3715 :
3716 0 : case 'H': length = slprintf(buffer, 32, "%02d", (int) t->h); break;
3717 0 : case 'h': length = slprintf(buffer, 32, "%d", (int) t->h); break;
3718 :
3719 0 : case 'I': length = slprintf(buffer, 32, "%02d", (int) t->i); break;
3720 0 : case 'i': length = slprintf(buffer, 32, "%d", (int) t->i); break;
3721 :
3722 0 : case 'S': length = slprintf(buffer, 32, "%02d", (int) t->s); break;
3723 0 : case 's': length = slprintf(buffer, 32, "%d", (int) t->s); break;
3724 :
3725 0 : case 'a': length = slprintf(buffer, 32, "%d", (int) t->days); break;
3726 0 : case 'r': length = slprintf(buffer, 32, "%s", t->invert ? "-" : ""); break;
3727 0 : case 'R': length = slprintf(buffer, 32, "%c", t->invert ? '-' : '+'); break;
3728 :
3729 0 : case '%': length = slprintf(buffer, 32, "%%"); break;
3730 0 : default: buffer[0] = '%'; buffer[1] = format[i]; buffer[2] = '\0'; length = 2; break;
3731 : }
3732 0 : smart_str_appendl(&string, buffer, length);
3733 0 : have_format_spec = 0;
3734 : } else {
3735 0 : if (format[i] == '%') {
3736 0 : have_format_spec = 1;
3737 : } else {
3738 0 : smart_str_appendc(&string, format[i]);
3739 : }
3740 : }
3741 : }
3742 :
3743 0 : smart_str_0(&string);
3744 :
3745 0 : return string.c;
3746 : }
3747 : /* }}} */
3748 :
3749 : /* {{{ proto string date_interval_format(DateInterval object, string format) U
3750 : Formats the interval.
3751 : */
3752 : PHP_FUNCTION(date_interval_format)
3753 0 : {
3754 : zval *object;
3755 : php_interval_obj *diobj;
3756 : char *format;
3757 : int format_len;
3758 :
3759 0 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_interval, &format, &format_len) == FAILURE) {
3760 0 : RETURN_FALSE;
3761 : }
3762 0 : diobj = (php_interval_obj *) zend_object_store_get_object(object TSRMLS_CC);
3763 0 : DATE_CHECK_INITIALIZED(diobj->initialized, DateInterval);
3764 :
3765 0 : RETURN_ASCII_STRING(date_interval_format(format, format_len, diobj->diff), ZSTR_AUTOFREE);
3766 : }
3767 : /* }}} */
3768 :
3769 : static int date_period_initialize(timelib_time **st, timelib_time **et, timelib_rel_time **d, int *recurrences, /*const*/ char *format, int format_length TSRMLS_DC)
3770 1 : {
3771 1 : timelib_time *b = NULL, *e = NULL;
3772 1 : timelib_rel_time *p = NULL;
3773 1 : int r = 0;
3774 1 : int retval = 0;
3775 : struct timelib_error_container *errors;
3776 :
3777 1 : timelib_strtointerval(format, format_length, &b, &e, &p, &r, &errors);
3778 :
3779 1 : if (errors->error_count > 0) {
3780 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or bad format (%s)", format);
3781 1 : retval = FAILURE;
3782 : } else {
3783 0 : *st = b;
3784 0 : *et = e;
3785 0 : *d = p;
3786 0 : *recurrences = r;
3787 0 : retval = SUCCESS;
3788 : }
3789 1 : timelib_error_container_dtor(errors);
3790 1 : return retval;
3791 : }
3792 :
3793 : /* {{{ proto DatePeriod::__construct(DateTime $start, DateInterval $interval, int recurrences|DateTime $end)
3794 : Creates new DatePeriod object.
3795 : */
3796 : PHP_METHOD(DatePeriod, __construct)
3797 5 : {
3798 : php_period_obj *dpobj;
3799 : php_date_obj *dateobj;
3800 : php_interval_obj *intobj;
3801 5 : zval *start, *end = NULL, *interval;
3802 5 : long recurrences = 0, options = 0;
3803 5 : char *isostr = NULL;
3804 5 : int isostr_len = 0;
3805 : timelib_time *clone;
3806 : zend_error_handling error_handling;
3807 :
3808 5 : zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
3809 5 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "OOl|l", &start, date_ce_date, &interval, date_ce_interval, &recurrences, &options) == FAILURE) {
3810 4 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "OOO|l", &start, date_ce_date, &interval, date_ce_interval, &end, date_ce_date, &options) == FAILURE) {
3811 2 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &isostr, &isostr_len, &options) == FAILURE) {
3812 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "This constructor accepts either (DateTime, DateInterval, int) OR (DateTime, DateInterval, DateTime) OR (string) as arguments.");
3813 1 : zend_restore_error_handling(&error_handling TSRMLS_CC);
3814 1 : return;
3815 : }
3816 : }
3817 : }
3818 :
3819 4 : dpobj = zend_object_store_get_object(getThis() TSRMLS_CC);
3820 :
3821 4 : if (isostr_len) {
3822 1 : date_period_initialize(&(dpobj->start), &(dpobj->end), &(dpobj->interval), (int*) &recurrences, isostr, isostr_len TSRMLS_CC);
3823 1 : if (dpobj->start == NULL) {
3824 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "The ISO interval '%s' did not contain a start date.", isostr);
3825 : }
3826 1 : if (dpobj->interval == NULL) {
3827 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "The ISO interval '%s' did not contain an interval.", isostr);
3828 : }
3829 1 : if (dpobj->end == NULL && recurrences == 0) {
3830 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "The ISO interval '%s' did not contain an end date or a recurrence count.", isostr);
3831 : }
3832 :
3833 1 : if (dpobj->start) {
3834 0 : timelib_update_ts(dpobj->start, NULL);
3835 : }
3836 1 : if (dpobj->end) {
3837 0 : timelib_update_ts(dpobj->end, NULL);
3838 : }
3839 : } else {
3840 : /* init */
3841 3 : intobj = (php_interval_obj *) zend_object_store_get_object(interval TSRMLS_CC);
3842 :
3843 : /* start date */
3844 3 : dateobj = (php_date_obj *) zend_object_store_get_object(start TSRMLS_CC);
3845 3 : clone = timelib_time_ctor();
3846 3 : memcpy(clone, dateobj->time, sizeof(timelib_time));
3847 3 : if (dateobj->time->tz_abbr) {
3848 3 : clone->tz_abbr = strdup(dateobj->time->tz_abbr);
3849 : }
3850 3 : if (dateobj->time->tz_info) {
3851 3 : clone->tz_info = dateobj->time->tz_info;
3852 : }
3853 3 : dpobj->start = clone;
3854 :
3855 : /* interval */
3856 3 : dpobj->interval = timelib_rel_time_clone(intobj->diff);
3857 :
3858 : /* end date */
3859 3 : if (end) {
3860 2 : dateobj = (php_date_obj *) zend_object_store_get_object(end TSRMLS_CC);
3861 2 : clone = timelib_time_ctor();
3862 2 : memcpy(clone, dateobj->time, sizeof(timelib_time));
3863 2 : if (dateobj->time->tz_abbr) {
3864 2 : clone->tz_abbr = strdup(dateobj->time->tz_abbr);
3865 : }
3866 2 : if (dateobj->time->tz_info) {
3867 2 : clone->tz_info = dateobj->time->tz_info;
3868 : }
3869 2 : dpobj->end = clone;
3870 : }
3871 : }
3872 :
3873 : /* options */
3874 4 : dpobj->include_start_date = !(options & PHP_DATE_PERIOD_EXCLUDE_START_DATE);
3875 :
3876 : /* recurrrences */
3877 4 : dpobj->recurrences = recurrences + dpobj->include_start_date;
3878 :
3879 4 : dpobj->initialized = 1;
3880 4 : zend_restore_error_handling(&error_handling TSRMLS_CC);
3881 : }
3882 : /* }}} */
3883 :
3884 : static int check_id_allowed(char *id, long what)
3885 2805 : {
3886 2805 : if (what & PHP_DATE_TIMEZONE_GROUP_AFRICA && strncasecmp(id, "Africa/", 7) == 0) return 1;
3887 2646 : if (what & PHP_DATE_TIMEZONE_GROUP_AMERICA && strncasecmp(id, "America/", 8) == 0) return 1;
3888 2030 : if (what & PHP_DATE_TIMEZONE_GROUP_ANTARCTICA && strncasecmp(id, "Antarctica/", 11) == 0) return 1;
3889 2000 : if (what & PHP_DATE_TIMEZONE_GROUP_ARCTIC && strncasecmp(id, "Arctic/", 7) == 0) return 1;
3890 1997 : if (what & PHP_DATE_TIMEZONE_GROUP_ASIA && strncasecmp(id, "Asia/", 5) == 0) return 1;
3891 1733 : if (what & PHP_DATE_TIMEZONE_GROUP_ATLANTIC && strncasecmp(id, "Atlantic/", 9) == 0) return 1;
3892 1697 : if (what & PHP_DATE_TIMEZONE_GROUP_AUSTRALIA && strncasecmp(id, "Australia/", 10) == 0) return 1;
3893 1628 : if (what & PHP_DATE_TIMEZONE_GROUP_EUROPE && strncasecmp(id, "Europe/", 7) == 0) return 1;
3894 1396 : if (what & PHP_DATE_TIMEZONE_GROUP_INDIAN && strncasecmp(id, "Indian/", 7) == 0) return 1;
3895 1363 : if (what & PHP_DATE_TIMEZONE_GROUP_PACIFIC && strncasecmp(id, "Pacific/", 8) == 0) return 1;
3896 1243 : if (what & PHP_DATE_TIMEZONE_GROUP_UTC && strncasecmp(id, "UTC", 3) == 0) return 1;
3897 1239 : return 0;
3898 : }
3899 :
3900 : /* {{{ proto array timezone_identifiers_list([long what[, string country]]) U
3901 : Returns numerically index array with all timezone identifiers.
3902 : */
3903 : PHP_FUNCTION(timezone_identifiers_list)
3904 7 : {
3905 : const timelib_tzdb *tzdb;
3906 : const timelib_tzdb_index_entry *table;
3907 : int i, item_count;
3908 7 : long what = PHP_DATE_TIMEZONE_GROUP_ALL;
3909 7 : char *option = NULL;
3910 7 : int option_len = 0;
3911 :
3912 7 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ls", &what, &option, &option_len) == FAILURE) {
3913 0 : RETURN_FALSE;
3914 : }
3915 :
3916 : /* Extra validation */
3917 7 : if (what == PHP_DATE_TIMEZONE_PER_COUNTRY && option_len != 2) {
3918 1 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "A two-letter ISO 3166-1 compatible country code is expected");
3919 1 : RETURN_FALSE;
3920 : }
3921 :
3922 6 : tzdb = DATE_TIMEZONEDB;
3923 6 : item_count = tzdb->index_size;
3924 6 : table = tzdb->index;
3925 :
3926 6 : array_init(return_value);
3927 :
3928 3372 : for (i = 0; i < item_count; ++i) {
3929 3366 : if (what == PHP_DATE_TIMEZONE_PER_COUNTRY) {
3930 0 : if (tzdb->data[table[i].pos + 5] == option[0] && tzdb->data[table[i].pos + 6] == option[1]) {
3931 0 : add_next_index_ascii_string(return_value, table[i].id, 1);
3932 : }
3933 3366 : } else if (what == PHP_DATE_TIMEZONE_GROUP_ALL_W_BC || (check_id_allowed(table[i].id, what) && (tzdb->data[table[i].pos + 4] == '\1'))) {
3934 1964 : add_next_index_ascii_string(return_value, table[i].id, 1);
3935 : }
3936 : };
3937 : }
3938 : /* }}} */
3939 :
3940 : /* {{{ proto array timezone_version_get()
3941 : Returns the Olson database version number.
3942 : */
3943 : PHP_FUNCTION(timezone_version_get)
3944 0 : {
3945 : const timelib_tzdb *tzdb;
3946 :
3947 0 : tzdb = DATE_TIMEZONEDB;
3948 0 : RETURN_ASCII_STRING(tzdb->version, 1);
3949 : }
3950 : /* }}} */
3951 :
3952 : /* {{{ proto array timezone_abbreviations_list() U
3953 : Returns associative array containing dst, offset and the timezone name
3954 : */
3955 : PHP_FUNCTION(timezone_abbreviations_list)
3956 3 : {
3957 : const timelib_tz_lookup_table *table, *entry;
3958 : zval *element, **abbr_array_pp, *abbr_array;
3959 :
3960 3 : table = timelib_timezone_abbreviations_list();
3961 3 : array_init(return_value);
3962 3 : entry = table;
3963 :
3964 : do {
3965 5094 : MAKE_STD_ZVAL(element);
3966 5094 : array_init(element);
3967 5094 : add_ascii_assoc_bool(element, "dst", entry->type);
3968 5094 : add_ascii_assoc_long(element, "offset", entry->gmtoffset);
3969 5094 : if (entry->full_tz_name) {
3970 5019 : add_ascii_assoc_ascii_string(element, "timezone_id", entry->full_tz_name, 1);
3971 : } else {
3972 75 : add_ascii_assoc_null(element, "timezone_id");
3973 : }
3974 :
3975 5094 : if (zend_ascii_hash_find(HASH_OF(return_value), entry->name, strlen(entry->name) + 1, (void **) &abbr_array_pp) == FAILURE) {
3976 1014 : MAKE_STD_ZVAL(abbr_array);
3977 1014 : array_init(abbr_array);
3978 1014 : add_ascii_assoc_zval(return_value, entry->name, abbr_array);
3979 : } else {
3980 4080 : abbr_array = *abbr_array_pp;
3981 : }
3982 5094 : add_next_index_zval(abbr_array, element);
3983 5094 : entry++;
3984 5094 : } while (entry->name);
3985 3 : }
3986 : /* }}} */
3987 :
3988 : /* {{{ proto bool date_default_timezone_set(string timezone_identifier) U
3989 : Sets the default timezone used by all date/time functions in a script */
3990 : PHP_FUNCTION(date_default_timezone_set)
3991 577 : {
3992 : char *zone;
3993 : int zone_len;
3994 :
3995 577 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &zone, &zone_len) == FAILURE) {
3996 4 : RETURN_FALSE;
3997 : }
3998 573 : if (!timelib_timezone_id_is_valid(zone, DATE_TIMEZONEDB)) {
3999 25 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Timezone ID '%s' is invalid", zone);
4000 25 : RETURN_FALSE;
4001 : }
4002 548 : if (DATEG(timezone)) {
4003 123 : efree(DATEG(timezone));
4004 123 : DATEG(timezone) = NULL;
4005 : }
4006 548 : DATEG(timezone) = estrndup(zone, zone_len);
4007 548 : RETURN_TRUE;
4008 : }
4009 : /* }}} */
4010 :
4011 : /* {{{ proto string date_default_timezone_get() U
4012 : Gets the default timezone used by all date/time functions in a script */
4013 : PHP_FUNCTION(date_default_timezone_get)
4014 11 : {
4015 : timelib_tzinfo *default_tz;
4016 :
4017 11 : default_tz = get_timezone_info(TSRMLS_C);
4018 11 : RETVAL_ASCII_STRING(default_tz->name, 1);
4019 11 : }
4020 : /* }}} */
4021 :
4022 : /* {{{ php_do_date_sunrise_sunset
4023 : * Common for date_sunrise() and date_sunset() functions
4024 : */
4025 : static void php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAMETERS, int calc_sunset)
4026 964 : {
4027 964 : double latitude = 0.0, longitude = 0.0, zenith = 0.0, gmt_offset = 0, altitude;
4028 : double h_rise, h_set, N;
4029 : timelib_sll rise, set, transit;
4030 964 : long time, retformat = 0;
4031 : int rs;
4032 : timelib_time *t;
4033 : timelib_tzinfo *tzi;
4034 : char retstr[6];
4035 :
4036 964 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|ldddd", &time, &retformat, &latitude, &longitude, &zenith, &gmt_offset) == FAILURE) {
4037 390 : RETURN_FALSE;
4038 : }
4039 :
4040 574 : switch (ZEND_NUM_ARGS()) {
4041 : case 1:
4042 0 : retformat = SUNFUNCS_RET_STRING;
4043 : case 2:
4044 0 : latitude = INI_FLT("date.default_latitude");
4045 : case 3:
4046 0 : longitude = INI_FLT("date.default_longitude");
4047 : case 4:
4048 48 : if (calc_sunset) {
4049 24 : zenith = INI_FLT("date.sunset_zenith");
4050 : } else {
4051 24 : zenith = INI_FLT("date.sunrise_zenith");
4052 : }
4053 : case 5:
4054 : case 6:
4055 : break;
4056 : default:
4057 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid format");
4058 0 : RETURN_FALSE;
4059 : break;
4060 : }
4061 964 : if (retformat != SUNFUNCS_RET_TIMESTAMP &&
4062 : retformat != SUNFUNCS_RET_STRING &&
4063 : retformat != SUNFUNCS_RET_DOUBLE)
4064 : {
4065 8 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Wrong return format given, pick one of SUNFUNCS_RET_TIMESTAMP, SUNFUNCS_RET_STRING or SUNFUNCS_RET_DOUBLE");
4066 8 : RETURN_FALSE;
4067 : }
4068 566 : altitude = 90 - zenith;
4069 :
4070 : /* Initialize time struct */
4071 566 : t = timelib_time_ctor();
4072 566 : tzi = get_timezone_info(TSRMLS_C);
4073 566 : t->tz_info = tzi;
4074 566 : t->zone_type = TIMELIB_ZONETYPE_ID;
4075 :
4076 566 : if (ZEND_NUM_ARGS() <= 5) {
4077 48 : gmt_offset = timelib_get_current_offset(t) / 3600;
4078 : }
4079 :
4080 566 : timelib_unixtime2local(t, time);
4081 566 : rs = timelib_astro_rise_set_altitude(t, longitude, latitude, altitude, 1, &h_rise, &h_set, &rise, &set, &transit);
4082 566 : timelib_time_dtor(t);
4083 :
4084 566 : if (rs != 0) {
4085 120 : RETURN_FALSE;
4086 : }
4087 :
4088 446 : if (retformat == SUNFUNCS_RET_TIMESTAMP) {
4089 144 : RETURN_LONG(calc_sunset ? set : rise);
4090 : }
4091 302 : N = (calc_sunset ? h_set : h_rise) + gmt_offset;
4092 :
4093 302 : if (N > 24 || N < 0) {
4094 28 : N -= floor(N / 24) * 24;
4095 : }
4096 :
4097 302 : switch (retformat) {
4098 : case SUNFUNCS_RET_STRING:
4099 172 : sprintf(retstr, "%02d:%02d", (int) N, (int) (60 * (N - (int) N)));
4100 172 : RETURN_RT_STRINGL(retstr, 5, 1);
4101 : break;
4102 : case SUNFUNCS_RET_DOUBLE:
4103 130 : RETURN_DOUBLE(N);
4104 : break;
4105 : }
4106 : }
4107 : /* }}} */
4108 :
4109 : /* {{{ proto mixed date_sunrise(mixed time [, int format [, float latitude [, float longitude [, float zenith [, float gmt_offset]]]]]) U
4110 : Returns time of sunrise for a given day and location */
4111 : PHP_FUNCTION(date_sunrise)
4112 481 : {
4113 481 : php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
4114 481 : }
4115 : /* }}} */
4116 :
4117 : /* {{{ proto mixed date_sunset(mixed time [, int format [, float latitude [, float longitude [, float zenith [, float gmt_offset]]]]]) U
4118 : Returns time of sunset for a given day and location */
4119 : PHP_FUNCTION(date_sunset)
4120 483 : {
4121 483 : php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
4122 483 : }
4123 : /* }}} */
4124 :
4125 : /* {{{ proto array date_sun_info(long time, float latitude, float longitude) U
4126 : Returns an array with information about sun set/rise and twilight begin/end */
4127 : PHP_FUNCTION(date_sun_info)
4128 76 : {
4129 : long time;
4130 : double latitude, longitude;
4131 : timelib_time *t, *t2;
4132 : timelib_tzinfo *tzi;
4133 : int rs;
4134 : timelib_sll rise, set, transit;
4135 : int dummy;
4136 : double ddummy;
4137 :
4138 76 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ldd", &time, &latitude, &longitude) == FAILURE) {
4139 24 : RETURN_FALSE;
4140 : }
4141 : /* Initialize time struct */
4142 52 : t = timelib_time_ctor();
4143 52 : tzi = get_timezone_info(TSRMLS_C);
4144 52 : t->tz_info = tzi;
4145 52 : t->zone_type = TIMELIB_ZONETYPE_ID;
4146 52 : timelib_unixtime2local(t, time);
4147 :
4148 : /* Setup */
4149 52 : t2 = timelib_time_ctor();
4150 52 : array_init(return_value);
4151 :
4152 : /* Get sun up/down and transit */
4153 52 : rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -35.0/60, 1, &ddummy, &ddummy, &rise, &set, &transit);
4154 52 : switch (rs) {
4155 : case -1: /* always below */
4156 0 : add_ascii_assoc_bool(return_value, "sunrise", 0);
4157 0 : add_ascii_assoc_bool(return_value, "sunset", 0);
4158 0 : break;
4159 : case 1: /* always above */
4160 1 : add_ascii_assoc_bool(return_value, "sunrise", 1);
4161 1 : add_ascii_assoc_bool(return_value, "sunset", 1);
4162 1 : break;
4163 : default:
4164 51 : t2->sse = rise;
4165 51 : add_ascii_assoc_long(return_value, "sunrise", timelib_date_to_int(t2, &dummy));
4166 51 : t2->sse = set;
4167 51 : add_ascii_assoc_long(return_value, "sunset", timelib_date_to_int(t2, &dummy));
4168 : }
4169 52 : t2->sse = transit;
4170 52 : add_ascii_assoc_long(return_value, "transit", timelib_date_to_int(t2, &dummy));
4171 :
4172 : /* Get civil twilight */
4173 52 : rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -6.0, 0, &ddummy, &ddummy, &rise, &set, &transit);
4174 52 : switch (rs) {
4175 : case -1: /* always below */
4176 0 : add_ascii_assoc_bool(return_value, "civil_twilight_begin", 0);
4177 0 : add_ascii_assoc_bool(return_value, "civil_twilight_end", 0);
4178 0 : break;
4179 : case 1: /* always above */
4180 1 : add_ascii_assoc_bool(return_value, "civil_twilight_begin", 1);
4181 1 : add_ascii_assoc_bool(return_value, "civil_twilight_end", 1);
4182 1 : break;
4183 : default:
4184 51 : t2->sse = rise;
4185 51 : add_ascii_assoc_long(return_value, "civil_twilight_begin", timelib_date_to_int(t2, &dummy));
4186 51 : t2->sse = set;
4187 51 : add_ascii_assoc_long(return_value, "civil_twilight_end", timelib_date_to_int(t2, &dummy));
4188 : }
4189 :
4190 : /* Get nautical twilight */
4191 52 : rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -12.0, 0, &ddummy, &ddummy, &rise, &set, &transit);
4192 52 : switch (rs) {
4193 : case -1: /* always below */
4194 0 : add_ascii_assoc_bool(return_value, "nautical_twilight_begin", 0);
4195 0 : add_ascii_assoc_bool(return_value, "nautical_twilight_end", 0);
4196 0 : break;
4197 : case 1: /* always above */
4198 0 : add_ascii_assoc_bool(return_value, "nautical_twilight_begin", 1);
4199 0 : add_ascii_assoc_bool(return_value, "nautical_twilight_end", 1);
4200 0 : break;
4201 : default:
4202 52 : t2->sse = rise;
4203 52 : add_ascii_assoc_long(return_value, "nautical_twilight_begin", timelib_date_to_int(t2, &dummy));
4204 52 : t2->sse = set;
4205 52 : add_ascii_assoc_long(return_value, "nautical_twilight_end", timelib_date_to_int(t2, &dummy));
4206 : }
4207 :
4208 : /* Get astronomical twilight */
4209 52 : rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -18.0, 0, &ddummy, &ddummy, &rise, &set, &transit);
4210 52 : switch (rs) {
4211 : case -1: /* always below */
4212 0 : add_ascii_assoc_bool(return_value, "astronomical_twilight_begin", 0);
4213 0 : add_ascii_assoc_bool(return_value, "astronomical_twilight_end", 0);
4214 0 : break;
4215 : case 1: /* always above */
4216 0 : add_ascii_assoc_bool(return_value, "astronomical_twilight_begin", 1);
4217 0 : add_ascii_assoc_bool(return_value, "astronomical_twilight_end", 1);
4218 0 : break;
4219 : default:
4220 52 : t2->sse = rise;
4221 52 : add_ascii_assoc_long(return_value, "astronomical_twilight_begin", timelib_date_to_int(t2, &dummy));
4222 52 : t2->sse = set;
4223 52 : add_ascii_assoc_long(return_value, "astronomical_twilight_end", timelib_date_to_int(t2, &dummy));
4224 : }
4225 52 : timelib_time_dtor(t);
4226 52 : timelib_time_dtor(t2);
4227 : }
4228 : /* }}} */
4229 : /*
4230 : * Local variables:
4231 : * tab-width: 4
4232 : * c-basic-offset: 4
4233 : * End:
4234 : * vim600: fdm=marker
4235 : * vim: noet sw=4 ts=4
4236 : */
|