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