1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Authors: Derick Rethans <derick@derickrethans.nl> |
16 : +----------------------------------------------------------------------+
17 : */
18 :
19 : /* $Id: php_date.c 289991 2009-10-27 16:21:03Z felipe $ */
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 "lib/timelib.h"
31 : #include <time.h>
32 :
33 : #ifdef PHP_WIN32
34 : static __inline __int64 llabs( __int64 i ) { return i >= 0? i: -i; }
35 : #endif
36 :
37 : #if defined(__GNUC__) && __GNUC__ < 3
38 : static __inline __int64_t llabs( __int64_t i ) { return i >= 0 ? i : -i; }
39 : #endif
40 :
41 : #if defined(NETWARE) && defined(__MWERKS__)
42 : static __inline long long llabs( long long i ) { return i >= 0 ? i : -i; }
43 : #endif
44 :
45 : /* {{{ arginfo */
46 : static
47 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date, 0, 0, 1)
48 : ZEND_ARG_INFO(0, format)
49 : ZEND_ARG_INFO(0, timestamp)
50 : ZEND_END_ARG_INFO()
51 :
52 : static
53 : ZEND_BEGIN_ARG_INFO_EX(arginfo_gmdate, 0, 0, 1)
54 : ZEND_ARG_INFO(0, format)
55 : ZEND_ARG_INFO(0, timestamp)
56 : ZEND_END_ARG_INFO()
57 :
58 : static
59 : ZEND_BEGIN_ARG_INFO_EX(arginfo_idate, 0, 0, 1)
60 : ZEND_ARG_INFO(0, format)
61 : ZEND_ARG_INFO(0, timestamp)
62 : ZEND_END_ARG_INFO()
63 :
64 : static
65 : ZEND_BEGIN_ARG_INFO_EX(arginfo_strtotime, 0, 0, 1)
66 : ZEND_ARG_INFO(0, time)
67 : ZEND_ARG_INFO(0, now)
68 : ZEND_END_ARG_INFO()
69 :
70 : static
71 : ZEND_BEGIN_ARG_INFO_EX(arginfo_mktime, 0, 0, 0)
72 : ZEND_ARG_INFO(0, hour)
73 : ZEND_ARG_INFO(0, min)
74 : ZEND_ARG_INFO(0, sec)
75 : ZEND_ARG_INFO(0, mon)
76 : ZEND_ARG_INFO(0, day)
77 : ZEND_ARG_INFO(0, year)
78 : ZEND_END_ARG_INFO()
79 :
80 : static
81 : ZEND_BEGIN_ARG_INFO_EX(arginfo_gmmktime, 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_END_ARG_INFO()
89 :
90 : static
91 : ZEND_BEGIN_ARG_INFO(arginfo_checkdate, 0)
92 : ZEND_ARG_INFO(0, month)
93 : ZEND_ARG_INFO(0, day)
94 : ZEND_ARG_INFO(0, year)
95 : ZEND_END_ARG_INFO()
96 :
97 : static
98 : ZEND_BEGIN_ARG_INFO_EX(arginfo_strftime, 0, 0, 1)
99 : ZEND_ARG_INFO(0, format)
100 : ZEND_ARG_INFO(0, timestamp)
101 : ZEND_END_ARG_INFO()
102 :
103 : static
104 : ZEND_BEGIN_ARG_INFO_EX(arginfo_gmstrftime, 0, 0, 1)
105 : ZEND_ARG_INFO(0, format)
106 : ZEND_ARG_INFO(0, timestamp)
107 : ZEND_END_ARG_INFO()
108 :
109 : static
110 : ZEND_BEGIN_ARG_INFO(arginfo_time, 0)
111 : ZEND_END_ARG_INFO()
112 :
113 : static
114 : ZEND_BEGIN_ARG_INFO_EX(arginfo_localtime, 0, 0, 0)
115 : ZEND_ARG_INFO(0, timestamp)
116 : ZEND_ARG_INFO(0, associative_array)
117 : ZEND_END_ARG_INFO()
118 :
119 : static
120 : ZEND_BEGIN_ARG_INFO_EX(arginfo_getdate, 0, 0, 0)
121 : ZEND_ARG_INFO(0, timestamp)
122 : ZEND_END_ARG_INFO()
123 :
124 : static
125 : ZEND_BEGIN_ARG_INFO(arginfo_date_default_timezone_set, 0)
126 : ZEND_ARG_INFO(0, timezone_identifier)
127 : ZEND_END_ARG_INFO()
128 :
129 : static
130 : ZEND_BEGIN_ARG_INFO(arginfo_date_default_timezone_get, 0)
131 : ZEND_END_ARG_INFO()
132 :
133 : static
134 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_sunrise, 0, 0, 1)
135 : ZEND_ARG_INFO(0, time)
136 : ZEND_ARG_INFO(0, format)
137 : ZEND_ARG_INFO(0, latitude)
138 : ZEND_ARG_INFO(0, longitude)
139 : ZEND_ARG_INFO(0, zenith)
140 : ZEND_ARG_INFO(0, gmt_offset)
141 : ZEND_END_ARG_INFO()
142 :
143 : static
144 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_sunset, 0, 0, 1)
145 : ZEND_ARG_INFO(0, time)
146 : ZEND_ARG_INFO(0, format)
147 : ZEND_ARG_INFO(0, latitude)
148 : ZEND_ARG_INFO(0, longitude)
149 : ZEND_ARG_INFO(0, zenith)
150 : ZEND_ARG_INFO(0, gmt_offset)
151 : ZEND_END_ARG_INFO()
152 :
153 : static
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 : /* }}} */
161 :
162 : /* {{{ Function table */
163 : zend_function_entry date_functions[] = {
164 : PHP_FE(strtotime, arginfo_strtotime)
165 : PHP_FE(date, arginfo_date)
166 : PHP_FE(idate, arginfo_idate)
167 : PHP_FE(gmdate, arginfo_gmdate)
168 : PHP_FE(mktime, arginfo_mktime)
169 : PHP_FE(gmmktime, arginfo_gmmktime)
170 : PHP_FE(checkdate, arginfo_checkdate)
171 :
172 : #ifdef HAVE_STRFTIME
173 : PHP_FE(strftime, arginfo_strftime)
174 : PHP_FE(gmstrftime, arginfo_gmstrftime)
175 : #endif
176 :
177 : PHP_FE(time, arginfo_time)
178 : PHP_FE(localtime, arginfo_localtime)
179 : PHP_FE(getdate, arginfo_getdate)
180 :
181 : /* Advanced Interface */
182 : PHP_FE(date_create, NULL)
183 : PHP_FE(date_parse, NULL)
184 : PHP_FE(date_format, NULL)
185 : PHP_FE(date_modify, NULL)
186 : PHP_FE(date_timezone_get, NULL)
187 : PHP_FE(date_timezone_set, NULL)
188 : PHP_FE(date_offset_get, NULL)
189 :
190 : PHP_FE(date_time_set, NULL)
191 : PHP_FE(date_date_set, NULL)
192 : PHP_FE(date_isodate_set, NULL)
193 :
194 : PHP_FE(timezone_open, NULL)
195 : PHP_FE(timezone_name_get, NULL)
196 : PHP_FE(timezone_name_from_abbr, NULL)
197 : PHP_FE(timezone_offset_get, NULL)
198 : PHP_FE(timezone_transitions_get, NULL)
199 : PHP_FE(timezone_identifiers_list, NULL)
200 : PHP_FE(timezone_abbreviations_list, NULL)
201 :
202 : /* Options and Configuration */
203 : PHP_FE(date_default_timezone_set, arginfo_date_default_timezone_set)
204 : PHP_FE(date_default_timezone_get, arginfo_date_default_timezone_get)
205 :
206 : /* Astronomical functions */
207 : PHP_FE(date_sunrise, arginfo_date_sunrise)
208 : PHP_FE(date_sunset, arginfo_date_sunset)
209 : PHP_FE(date_sun_info, arginfo_date_sun_info)
210 : {NULL, NULL, NULL}
211 : };
212 :
213 : zend_function_entry date_funcs_date[] = {
214 : PHP_ME(DateTime, __construct, NULL, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
215 : PHP_ME_MAPPING(format, date_format, NULL, 0)
216 : PHP_ME_MAPPING(modify, date_modify, NULL, 0)
217 : PHP_ME_MAPPING(getTimezone, date_timezone_get, NULL, 0)
218 : PHP_ME_MAPPING(setTimezone, date_timezone_set, NULL, 0)
219 : PHP_ME_MAPPING(getOffset, date_offset_get, NULL, 0)
220 : PHP_ME_MAPPING(setTime, date_time_set, NULL, 0)
221 : PHP_ME_MAPPING(setDate, date_date_set, NULL, 0)
222 : PHP_ME_MAPPING(setISODate, date_isodate_set, NULL, 0)
223 : {NULL, NULL, NULL}
224 : };
225 :
226 : zend_function_entry date_funcs_timezone[] = {
227 : PHP_ME(DateTimeZone, __construct, NULL, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
228 : PHP_ME_MAPPING(getName, timezone_name_get, NULL, 0)
229 : PHP_ME_MAPPING(getOffset, timezone_offset_get, NULL, 0)
230 : PHP_ME_MAPPING(getTransitions, timezone_transitions_get, NULL, 0)
231 : PHP_ME_MAPPING(listAbbreviations, timezone_abbreviations_list, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
232 : PHP_ME_MAPPING(listIdentifiers, timezone_identifiers_list, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
233 : {NULL, NULL, NULL}
234 : };
235 :
236 : static void date_register_classes(TSRMLS_D);
237 : static char* guess_timezone(const timelib_tzdb *tzdb TSRMLS_DC);
238 : /* }}} */
239 :
240 : ZEND_DECLARE_MODULE_GLOBALS(date)
241 : static PHP_GINIT_FUNCTION(date);
242 :
243 : /* True global */
244 : timelib_tzdb *php_date_global_timezone_db;
245 : int php_date_global_timezone_db_enabled;
246 :
247 : #define DATE_DEFAULT_LATITUDE "31.7667"
248 : #define DATE_DEFAULT_LONGITUDE "35.2333"
249 :
250 : /* on 90'35; common sunset declaration (start of sun body appear) */
251 : #define DATE_SUNSET_ZENITH "90.583333"
252 :
253 : /* on 90'35; common sunrise declaration (sun body disappeared) */
254 : #define DATE_SUNRISE_ZENITH "90.583333"
255 :
256 : /* {{{ INI Settings */
257 : PHP_INI_BEGIN()
258 : STD_PHP_INI_ENTRY("date.timezone", "", PHP_INI_ALL, OnUpdateString, default_timezone, zend_date_globals, date_globals)
259 : PHP_INI_ENTRY("date.default_latitude", DATE_DEFAULT_LATITUDE, PHP_INI_ALL, NULL)
260 : PHP_INI_ENTRY("date.default_longitude", DATE_DEFAULT_LONGITUDE, PHP_INI_ALL, NULL)
261 : PHP_INI_ENTRY("date.sunset_zenith", DATE_SUNSET_ZENITH, PHP_INI_ALL, NULL)
262 : PHP_INI_ENTRY("date.sunrise_zenith", DATE_SUNRISE_ZENITH, PHP_INI_ALL, NULL)
263 : PHP_INI_END()
264 : /* }}} */
265 :
266 : zend_class_entry *date_ce_date, *date_ce_timezone;
267 :
268 : static zend_object_handlers date_object_handlers_date;
269 : static zend_object_handlers date_object_handlers_timezone;
270 :
271 : typedef struct _php_date_obj php_date_obj;
272 : typedef struct _php_timezone_obj php_timezone_obj;
273 :
274 : struct _php_date_obj {
275 : zend_object std;
276 : timelib_time *time;
277 : };
278 :
279 : struct _php_timezone_obj {
280 : zend_object std;
281 : int initialized;
282 : int type;
283 : union {
284 : timelib_tzinfo *tz; /* TIMELIB_ZONETYPE_ID; */
285 : timelib_sll utc_offset; /* TIMELIB_ZONETYPE_OFFSET */
286 : struct /* TIMELIB_ZONETYPE_ABBR */
287 : {
288 : timelib_sll utc_offset;
289 : char *abbr;
290 : int dst;
291 : } z;
292 : } tzi;
293 : };
294 :
295 : #define DATE_SET_CONTEXT \
296 : zval *object; \
297 : object = getThis(); \
298 :
299 : #define DATE_FETCH_OBJECT \
300 : php_date_obj *obj; \
301 : DATE_SET_CONTEXT; \
302 : if (object) { \
303 : if (ZEND_NUM_ARGS()) { \
304 : WRONG_PARAM_COUNT; \
305 : } \
306 : } else { \
307 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, NULL, "O", &object, date_ce_date) == FAILURE) { \
308 : RETURN_FALSE; \
309 : } \
310 : } \
311 : obj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); \
312 :
313 : #define DATE_CHECK_INITIALIZED(member, class_name) \
314 : if (!(member)) { \
315 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "The " #class_name " object has not been correctly initialized by its constructor"); \
316 : RETURN_FALSE; \
317 : }
318 :
319 : static void date_object_free_storage_date(void *object TSRMLS_DC);
320 : static void date_object_free_storage_timezone(void *object TSRMLS_DC);
321 : static zend_object_value date_object_new_date(zend_class_entry *class_type TSRMLS_DC);
322 : static zend_object_value date_object_new_timezone(zend_class_entry *class_type TSRMLS_DC);
323 : static zend_object_value date_object_clone_date(zval *this_ptr TSRMLS_DC);
324 : static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC);
325 : static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC);
326 :
327 : /* {{{ Module struct */
328 : zend_module_entry date_module_entry = {
329 : STANDARD_MODULE_HEADER_EX,
330 : NULL,
331 : NULL,
332 : "date", /* extension name */
333 : date_functions, /* function list */
334 : PHP_MINIT(date), /* process startup */
335 : PHP_MSHUTDOWN(date), /* process shutdown */
336 : PHP_RINIT(date), /* request startup */
337 : PHP_RSHUTDOWN(date), /* request shutdown */
338 : PHP_MINFO(date), /* extension info */
339 : PHP_VERSION, /* extension version */
340 : PHP_MODULE_GLOBALS(date), /* globals descriptor */
341 : PHP_GINIT(date), /* globals ctor */
342 : NULL, /* globals dtor */
343 : NULL, /* post deactivate */
344 : STANDARD_MODULE_PROPERTIES_EX
345 : };
346 : /* }}} */
347 :
348 :
349 : /* {{{ PHP_GINIT_FUNCTION */
350 : static PHP_GINIT_FUNCTION(date)
351 13565 : {
352 13565 : date_globals->default_timezone = NULL;
353 13565 : date_globals->timezone = NULL;
354 13565 : date_globals->tzcache = NULL;
355 13565 : }
356 : /* }}} */
357 :
358 :
359 : static void _php_date_tzinfo_dtor(void *tzinfo)
360 468 : {
361 468 : timelib_tzinfo **tzi = (timelib_tzinfo **)tzinfo;
362 :
363 468 : timelib_tzinfo_dtor(*tzi);
364 468 : }
365 :
366 : /* {{{ PHP_RINIT_FUNCTION */
367 : PHP_RINIT_FUNCTION(date)
368 13551 : {
369 13551 : if (DATEG(timezone)) {
370 0 : efree(DATEG(timezone));
371 : }
372 13551 : DATEG(timezone) = NULL;
373 13551 : DATEG(tzcache) = NULL;
374 :
375 13551 : return SUCCESS;
376 : }
377 : /* }}} */
378 :
379 : /* {{{ PHP_RSHUTDOWN_FUNCTION */
380 : PHP_RSHUTDOWN_FUNCTION(date)
381 13584 : {
382 13584 : if (DATEG(timezone)) {
383 303 : efree(DATEG(timezone));
384 : }
385 13584 : DATEG(timezone) = NULL;
386 13584 : if(DATEG(tzcache)) {
387 326 : zend_hash_destroy(DATEG(tzcache));
388 326 : FREE_HASHTABLE(DATEG(tzcache));
389 326 : DATEG(tzcache) = NULL;
390 : }
391 :
392 13584 : return SUCCESS;
393 : }
394 : /* }}} */
395 :
396 : #define DATE_TIMEZONEDB php_date_global_timezone_db ? php_date_global_timezone_db : timelib_builtin_db()
397 :
398 : /*
399 : * RFC822, Section 5.1: http://www.ietf.org/rfc/rfc822.txt
400 : * date-time = [ day "," ] date time ; dd mm yy hh:mm:ss zzz
401 : * day = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"
402 : * date = 1*2DIGIT month 2DIGIT ; day month year e.g. 20 Jun 82
403 : * month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
404 : * time = hour zone ; ANSI and Military
405 : * hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT] ; 00:00:00 - 23:59:59
406 : * zone = "UT" / "GMT" / "EST" / "EDT" / "CST" / "CDT" / "MST" / "MDT" / "PST" / "PDT" / 1ALPHA / ( ("+" / "-") 4DIGIT )
407 : */
408 : #define DATE_FORMAT_RFC822 "D, d M y H:i:s O"
409 :
410 : /*
411 : * RFC850, Section 2.1.4: http://www.ietf.org/rfc/rfc850.txt
412 : * Format must be acceptable both to the ARPANET and to the getdate routine.
413 : * One format that is acceptable to both is Weekday, DD-Mon-YY HH:MM:SS TIMEZONE
414 : * TIMEZONE can be any timezone name (3 or more letters)
415 : */
416 : #define DATE_FORMAT_RFC850 "l, d-M-y H:i:s T"
417 :
418 : /*
419 : * RFC1036, Section 2.1.2: http://www.ietf.org/rfc/rfc1036.txt
420 : * Its format must be acceptable both in RFC-822 and to the getdate(3)
421 : * Wdy, DD Mon YY HH:MM:SS TIMEZONE
422 : * There is no hope of having a complete list of timezones. Universal
423 : * Time (GMT), the North American timezones (PST, PDT, MST, MDT, CST,
424 : * CDT, EST, EDT) and the +/-hhmm offset specifed in RFC-822 should be supported.
425 : */
426 : #define DATE_FORMAT_RFC1036 "D, d M y H:i:s O"
427 :
428 : /*
429 : * RFC1123, Section 5.2.14: http://www.ietf.org/rfc/rfc1123.txt
430 : * RFC-822 Date and Time Specification: RFC-822 Section 5
431 : * The syntax for the date is hereby changed to: date = 1*2DIGIT month 2*4DIGIT
432 : */
433 : #define DATE_FORMAT_RFC1123 "D, d M Y H:i:s O"
434 :
435 : /*
436 : * RFC2822, Section 3.3: http://www.ietf.org/rfc/rfc2822.txt
437 : * FWS = ([*WSP CRLF] 1*WSP) / ; Folding white space
438 : * CFWS = *([FWS] comment) (([FWS] comment) / FWS)
439 : *
440 : * date-time = [ day-of-week "," ] date FWS time [CFWS]
441 : * day-of-week = ([FWS] day-name)
442 : * day-name = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"
443 : * date = day month year
444 : * year = 4*DIGIT
445 : * month = (FWS month-name FWS)
446 : * month-name = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
447 : * day = ([FWS] 1*2DIGIT)
448 : * time = time-of-day FWS zone
449 : * time-of-day = hour ":" minute [ ":" second ]
450 : * hour = 2DIGIT
451 : * minute = 2DIGIT
452 : * second = 2DIGIT
453 : * zone = (( "+" / "-" ) 4DIGIT)
454 : */
455 : #define DATE_FORMAT_RFC2822 "D, d M Y H:i:s O"
456 : /*
457 : * RFC3339, Section 5.6: http://www.ietf.org/rfc/rfc3339.txt
458 : * date-fullyear = 4DIGIT
459 : * date-month = 2DIGIT ; 01-12
460 : * date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on month/year
461 : *
462 : * time-hour = 2DIGIT ; 00-23
463 : * time-minute = 2DIGIT ; 00-59
464 : * time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second rules
465 : *
466 : * time-secfrac = "." 1*DIGIT
467 : * time-numoffset = ("+" / "-") time-hour ":" time-minute
468 : * time-offset = "Z" / time-numoffset
469 : *
470 : * partial-time = time-hour ":" time-minute ":" time-second [time-secfrac]
471 : * full-date = date-fullyear "-" date-month "-" date-mday
472 : * full-time = partial-time time-offset
473 : *
474 : * date-time = full-date "T" full-time
475 : */
476 : #define DATE_FORMAT_RFC3339 "Y-m-d\\TH:i:sP"
477 :
478 : #define DATE_FORMAT_ISO8601 "Y-m-d\\TH:i:sO"
479 :
480 : #define DATE_TZ_ERRMSG \
481 : "It is not safe to rely on the system's timezone settings. Please use " \
482 : "the date.timezone setting, the TZ environment variable or the " \
483 : "date_default_timezone_set() function. In case you used any of those " \
484 : "methods and you are still getting this warning, you most likely " \
485 : "misspelled the timezone identifier. "
486 :
487 : #define SUNFUNCS_RET_TIMESTAMP 0
488 : #define SUNFUNCS_RET_STRING 1
489 : #define SUNFUNCS_RET_DOUBLE 2
490 :
491 :
492 : /* {{{ PHP_MINIT_FUNCTION */
493 : PHP_MINIT_FUNCTION(date)
494 13565 : {
495 13565 : REGISTER_INI_ENTRIES();
496 13565 : date_register_classes(TSRMLS_C);
497 : /*
498 : * RFC4287, Section 3.3: http://www.ietf.org/rfc/rfc4287.txt
499 : * A Date construct is an element whose content MUST conform to the
500 : * "date-time" production in [RFC3339]. In addition, an uppercase "T"
501 : * character MUST be used to separate date and time, and an uppercase
502 : * "Z" character MUST be present in the absence of a numeric time zone offset.
503 : */
504 13565 : REGISTER_STRING_CONSTANT("DATE_ATOM", DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
505 : /*
506 : * Preliminary specification: http://wp.netscape.com/newsref/std/cookie_spec.html
507 : * "This is based on RFC 822, RFC 850, RFC 1036, and RFC 1123,
508 : * with the variations that the only legal time zone is GMT
509 : * and the separators between the elements of the date must be dashes."
510 : */
511 13565 : REGISTER_STRING_CONSTANT("DATE_COOKIE", DATE_FORMAT_RFC850, CONST_CS | CONST_PERSISTENT);
512 13565 : REGISTER_STRING_CONSTANT("DATE_ISO8601", DATE_FORMAT_ISO8601, CONST_CS | CONST_PERSISTENT);
513 13565 : REGISTER_STRING_CONSTANT("DATE_RFC822", DATE_FORMAT_RFC822, CONST_CS | CONST_PERSISTENT);
514 13565 : REGISTER_STRING_CONSTANT("DATE_RFC850", DATE_FORMAT_RFC850, CONST_CS | CONST_PERSISTENT);
515 13565 : REGISTER_STRING_CONSTANT("DATE_RFC1036", DATE_FORMAT_RFC1036, CONST_CS | CONST_PERSISTENT);
516 13565 : REGISTER_STRING_CONSTANT("DATE_RFC1123", DATE_FORMAT_RFC1123, CONST_CS | CONST_PERSISTENT);
517 13565 : REGISTER_STRING_CONSTANT("DATE_RFC2822", DATE_FORMAT_RFC2822, CONST_CS | CONST_PERSISTENT);
518 13565 : REGISTER_STRING_CONSTANT("DATE_RFC3339", DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
519 : /*
520 : * RSS 2.0 Specification: http://blogs.law.harvard.edu/tech/rss
521 : * "All date-times in RSS conform to the Date and Time Specification of RFC 822,
522 : * with the exception that the year may be expressed with two characters or four characters (four preferred)"
523 : */
524 13565 : REGISTER_STRING_CONSTANT("DATE_RSS", DATE_FORMAT_RFC1123, CONST_CS | CONST_PERSISTENT);
525 13565 : REGISTER_STRING_CONSTANT("DATE_W3C", DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
526 :
527 13565 : REGISTER_LONG_CONSTANT("SUNFUNCS_RET_TIMESTAMP", SUNFUNCS_RET_TIMESTAMP, CONST_CS | CONST_PERSISTENT);
528 13565 : REGISTER_LONG_CONSTANT("SUNFUNCS_RET_STRING", SUNFUNCS_RET_STRING, CONST_CS | CONST_PERSISTENT);
529 13565 : REGISTER_LONG_CONSTANT("SUNFUNCS_RET_DOUBLE", SUNFUNCS_RET_DOUBLE, CONST_CS | CONST_PERSISTENT);
530 :
531 13565 : php_date_global_timezone_db = NULL;
532 13565 : php_date_global_timezone_db_enabled = 0;
533 :
534 13565 : return SUCCESS;
535 : }
536 : /* }}} */
537 :
538 : /* {{{ PHP_MSHUTDOWN_FUNCTION */
539 : PHP_MSHUTDOWN_FUNCTION(date)
540 13597 : {
541 13597 : UNREGISTER_INI_ENTRIES();
542 :
543 13597 : return SUCCESS;
544 : }
545 : /* }}} */
546 :
547 : /* {{{ PHP_MINFO_FUNCTION */
548 : PHP_MINFO_FUNCTION(date)
549 7 : {
550 7 : const timelib_tzdb *tzdb = DATE_TIMEZONEDB;
551 :
552 7 : php_info_print_table_start();
553 7 : php_info_print_table_row(2, "date/time support", "enabled");
554 7 : php_info_print_table_row(2, "\"Olson\" Timezone Database Version", tzdb->version);
555 7 : php_info_print_table_row(2, "Timezone Database", php_date_global_timezone_db_enabled ? "external" : "internal");
556 7 : php_info_print_table_row(2, "Default timezone", guess_timezone(tzdb TSRMLS_CC));
557 7 : php_info_print_table_end();
558 :
559 7 : DISPLAY_INI_ENTRIES();
560 7 : }
561 : /* }}} */
562 :
563 : /* {{{ Timezone Cache functions */
564 : static timelib_tzinfo *php_date_parse_tzfile(char *formal_tzname, const timelib_tzdb *tzdb TSRMLS_DC)
565 7181 : {
566 : timelib_tzinfo *tzi, **ptzi;
567 :
568 7181 : if(!DATEG(tzcache)) {
569 326 : ALLOC_HASHTABLE(DATEG(tzcache));
570 326 : zend_hash_init(DATEG(tzcache), 4, NULL, _php_date_tzinfo_dtor, 0);
571 : }
572 :
573 7181 : if (zend_hash_find(DATEG(tzcache), formal_tzname, strlen(formal_tzname) + 1, (void **) &ptzi) == SUCCESS) {
574 6668 : return *ptzi;
575 : }
576 :
577 513 : tzi = timelib_parse_tzfile(formal_tzname, tzdb);
578 513 : if (tzi) {
579 468 : zend_hash_add(DATEG(tzcache), formal_tzname, strlen(formal_tzname) + 1, (void *) &tzi, sizeof(timelib_tzinfo*), NULL);
580 : }
581 513 : return tzi;
582 : }
583 : /* }}} */
584 :
585 : /* {{{ Helper functions */
586 : static char* guess_timezone(const timelib_tzdb *tzdb TSRMLS_DC)
587 7082 : {
588 : char *env;
589 :
590 : /* Checking configure timezone */
591 7082 : if (DATEG(timezone) && (strlen(DATEG(timezone)) > 0)) {
592 5934 : return DATEG(timezone);
593 : }
594 : /* Check environment variable */
595 1148 : env = getenv("TZ");
596 1148 : if (env && *env && timelib_timezone_id_is_valid(env, tzdb)) {
597 888 : return env;
598 : }
599 : /* Check config setting for default timezone */
600 260 : if (!DATEG(default_timezone)) {
601 : /* Special case: ext/date wasn't initialized yet */
602 : zval ztz;
603 :
604 0 : if (SUCCESS == zend_get_configuration_directive("date.timezone", sizeof("date.timezone"), &ztz) &&
605 : Z_TYPE(ztz) == IS_STRING &&
606 : Z_STRLEN(ztz) > 0 &&
607 : timelib_timezone_id_is_valid(Z_STRVAL(ztz), tzdb)) {
608 0 : return Z_STRVAL(ztz);
609 : }
610 260 : } else if (*DATEG(default_timezone) && timelib_timezone_id_is_valid(DATEG(default_timezone), tzdb)) {
611 254 : return DATEG(default_timezone);
612 : }
613 : #if HAVE_TM_ZONE
614 : /* Try to guess timezone from system information */
615 : {
616 : struct tm *ta, tmbuf;
617 : time_t the_time;
618 6 : char *tzid = NULL;
619 :
620 6 : the_time = time(NULL);
621 6 : ta = php_localtime_r(&the_time, &tmbuf);
622 6 : if (ta) {
623 6 : tzid = timelib_timezone_id_from_abbr(ta->tm_zone, ta->tm_gmtoff, ta->tm_isdst);
624 : }
625 6 : if (! tzid) {
626 0 : tzid = "UTC";
627 : }
628 :
629 6 : php_error_docref(NULL TSRMLS_CC, E_STRICT, DATE_TZ_ERRMSG "We selected '%s' for '%s/%.1f/%s' instead", tzid, ta ? ta->tm_zone : "Unknown", ta ? (float) (ta->tm_gmtoff / 3600) : 0, ta ? (ta->tm_isdst ? "DST" : "no DST") : "Unknown");
630 6 : return tzid;
631 : }
632 : #endif
633 : #ifdef PHP_WIN32
634 : {
635 : char *tzid;
636 : TIME_ZONE_INFORMATION tzi;
637 :
638 : switch (GetTimeZoneInformation(&tzi))
639 : {
640 : /* no DST or not in effect */
641 : case TIME_ZONE_ID_UNKNOWN:
642 : case TIME_ZONE_ID_STANDARD:
643 : php_win_std_time:
644 : tzid = timelib_timezone_id_from_abbr("", (tzi.Bias + tzi.StandardBias) * -60, 0);
645 : if (! tzid) {
646 : tzid = "UTC";
647 : }
648 : php_error_docref(NULL TSRMLS_CC, E_STRICT, DATE_TZ_ERRMSG "We selected '%s' for '%.1f/no DST' instead", tzid, ((tzi.Bias + tzi.StandardBias) / -60.0));
649 : break;
650 :
651 : /* DST in effect */
652 : case TIME_ZONE_ID_DAYLIGHT:
653 : /* If user has disabled DST in the control panel, Windows returns 0 here */
654 : if (tzi.DaylightBias == 0) {
655 : goto php_win_std_time;
656 : }
657 :
658 : tzid = timelib_timezone_id_from_abbr("", (tzi.Bias + tzi.DaylightBias) * -60, 1);
659 : if (! tzid) {
660 : tzid = "UTC";
661 : }
662 : php_error_docref(NULL TSRMLS_CC, E_STRICT, DATE_TZ_ERRMSG "We selected '%s' for '%.1f/DST' instead", tzid, ((tzi.Bias + tzi.DaylightBias) / -60.0));
663 : break;
664 : }
665 : return tzid;
666 : }
667 : #elif defined(NETWARE)
668 : /* Try to guess timezone from system information */
669 : {
670 : char *tzid = timelib_timezone_id_from_abbr("", ((_timezone * -1) + (daylightOffset * daylightOnOff)), daylightOnOff);
671 : if (tzid) {
672 : return tzid;
673 : }
674 : }
675 : #endif
676 : /* Fallback to UTC */
677 : php_error_docref(NULL TSRMLS_CC, E_WARNING, DATE_TZ_ERRMSG "We had to select 'UTC' because your platform doesn't provide functionality for the guessing algorithm");
678 : return "UTC";
679 : }
680 :
681 : PHPAPI timelib_tzinfo *get_timezone_info(TSRMLS_D)
682 7075 : {
683 : char *tz;
684 : timelib_tzinfo *tzi;
685 :
686 7075 : tz = guess_timezone(DATE_TIMEZONEDB TSRMLS_CC);
687 7075 : tzi = php_date_parse_tzfile(tz, DATE_TIMEZONEDB TSRMLS_CC);
688 7075 : if (! tzi) {
689 0 : php_error_docref(NULL TSRMLS_CC, E_ERROR, "Timezone database is corrupt - this should *never* happen!");
690 : }
691 7075 : return tzi;
692 : }
693 : /* }}} */
694 :
695 :
696 : /* {{{ date() and gmdate() data */
697 : #include "ext/standard/php_smart_str.h"
698 :
699 : static char *mon_full_names[] = {
700 : "January", "February", "March", "April",
701 : "May", "June", "July", "August",
702 : "September", "October", "November", "December"
703 : };
704 :
705 : static char *mon_short_names[] = {
706 : "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
707 : };
708 :
709 : static char *day_full_names[] = {
710 : "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
711 : };
712 :
713 : static char *day_short_names[] = {
714 : "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
715 : };
716 :
717 : static char *english_suffix(timelib_sll number)
718 37 : {
719 37 : if (number >= 10 && number <= 19) {
720 13 : return "th";
721 : } else {
722 24 : switch (number % 10) {
723 4 : case 1: return "st";
724 2 : case 2: return "nd";
725 2 : case 3: return "rd";
726 : }
727 : }
728 16 : return "th";
729 : }
730 : /* }}} */
731 :
732 : /* {{{ day of week helpers */
733 : char *php_date_full_day_name(timelib_sll y, timelib_sll m, timelib_sll d)
734 235 : {
735 235 : timelib_sll day_of_week = timelib_day_of_week(y, m, d);
736 235 : if (day_of_week < 0) {
737 0 : return "Unknown";
738 : }
739 235 : return day_full_names[day_of_week];
740 : }
741 :
742 : char *php_date_short_day_name(timelib_sll y, timelib_sll m, timelib_sll d)
743 239 : {
744 239 : timelib_sll day_of_week = timelib_day_of_week(y, m, d);
745 239 : if (day_of_week < 0) {
746 0 : return "Unknown";
747 : }
748 239 : return day_short_names[day_of_week];
749 : }
750 : /* }}} */
751 :
752 : /* {{{ date_format - (gm)date helper */
753 : static char *date_format(char *format, int format_len, timelib_time *t, int localtime)
754 3951 : {
755 3951 : smart_str string = {0};
756 : int i, length;
757 : char buffer[33];
758 3951 : timelib_time_offset *offset = NULL;
759 : timelib_sll isoweek, isoyear;
760 : int rfc_colon;
761 :
762 3951 : if (!format_len) {
763 41 : return estrdup("");
764 : }
765 :
766 3910 : if (localtime) {
767 2997 : if (t->zone_type == TIMELIB_ZONETYPE_ABBR) {
768 11 : offset = timelib_time_offset_ctor();
769 11 : offset->offset = (t->z - (t->dst * 60)) * -60;
770 11 : offset->leap_secs = 0;
771 11 : offset->is_dst = t->dst;
772 11 : offset->abbr = strdup(t->tz_abbr);
773 2986 : } else if (t->zone_type == TIMELIB_ZONETYPE_OFFSET) {
774 17 : offset = timelib_time_offset_ctor();
775 17 : offset->offset = (t->z) * -60;
776 17 : offset->leap_secs = 0;
777 17 : offset->is_dst = 0;
778 17 : offset->abbr = malloc(9); /* GMT±xxxx\0 */
779 17 : snprintf(offset->abbr, 9, "GMT%c%02d%02d",
780 : localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
781 : localtime ? abs(offset->offset / 3600) : 0,
782 : localtime ? abs((offset->offset % 3600) / 60) : 0 );
783 : } else {
784 2969 : offset = timelib_get_time_zone_info(t->sse, t->tz_info);
785 : }
786 : }
787 3910 : timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear);
788 :
789 26263 : for (i = 0; i < format_len; i++) {
790 22353 : rfc_colon = 0;
791 22353 : switch (format[i]) {
792 : /* day */
793 1462 : case 'd': length = slprintf(buffer, 32, "%02d", (int) t->d); break;
794 204 : case 'D': length = slprintf(buffer, 32, "%s", php_date_short_day_name(t->y, t->m, t->d)); break;
795 82 : case 'j': length = slprintf(buffer, 32, "%d", (int) t->d); break;
796 198 : case 'l': length = slprintf(buffer, 32, "%s", php_date_full_day_name(t->y, t->m, t->d)); break;
797 37 : case 'S': length = slprintf(buffer, 32, "%s", english_suffix(t->d)); break;
798 12 : case 'w': length = slprintf(buffer, 32, "%d", (int) timelib_day_of_week(t->y, t->m, t->d)); break;
799 4 : case 'N': length = slprintf(buffer, 32, "%d", (int) timelib_iso_day_of_week(t->y, t->m, t->d)); break;
800 6 : case 'z': length = slprintf(buffer, 32, "%d", (int) timelib_day_of_year(t->y, t->m, t->d)); break;
801 :
802 : /* week */
803 1040 : case 'W': length = slprintf(buffer, 32, "%02d", (int) isoweek); break; /* iso weeknr */
804 1026 : case 'o': length = slprintf(buffer, 32, "%d", (int) isoyear); break; /* iso year */
805 :
806 : /* month */
807 51 : case 'F': length = slprintf(buffer, 32, "%s", mon_full_names[t->m - 1]); break;
808 1353 : case 'm': length = slprintf(buffer, 32, "%02d", (int) t->m); break;
809 183 : case 'M': length = slprintf(buffer, 32, "%s", mon_short_names[t->m - 1]); break;
810 18 : case 'n': length = slprintf(buffer, 32, "%d", (int) t->m); break;
811 20 : case 't': length = slprintf(buffer, 32, "%d", (int) timelib_days_in_month(t->y, t->m)); break;
812 :
813 : /* year */
814 10 : case 'L': length = slprintf(buffer, 32, "%d", timelib_is_leap((int) t->y)); break;
815 67 : case 'y': length = slprintf(buffer, 32, "%02d", (int) t->y % 100); break;
816 1503 : case 'Y': length = slprintf(buffer, 32, "%s%04lld", t->y < 0 ? "-" : "", llabs(t->y)); break;
817 :
818 : /* time */
819 38 : case 'a': length = slprintf(buffer, 32, "%s", t->h >= 12 ? "pm" : "am"); break;
820 7 : case 'A': length = slprintf(buffer, 32, "%s", t->h >= 12 ? "PM" : "AM"); break;
821 : case 'B': {
822 6 : int retval = (((((long)t->sse)-(((long)t->sse) - ((((long)t->sse) % 86400) + 3600))) * 10) / 864);
823 12 : while (retval < 0) {
824 0 : retval += 1000;
825 : }
826 6 : retval = retval % 1000;
827 6 : length = slprintf(buffer, 32, "%03d", retval);
828 6 : break;
829 : }
830 34 : case 'g': length = slprintf(buffer, 32, "%d", (t->h % 12) ? (int) t->h % 12 : 12); break;
831 12 : case 'G': length = slprintf(buffer, 32, "%d", (int) t->h); break;
832 23 : case 'h': length = slprintf(buffer, 32, "%02d", (t->h % 12) ? (int) t->h % 12 : 12); break;
833 1465 : case 'H': length = slprintf(buffer, 32, "%02d", (int) t->h); break;
834 1517 : case 'i': length = slprintf(buffer, 32, "%02d", (int) t->i); break;
835 1509 : case 's': length = slprintf(buffer, 32, "%02d", (int) t->s); break;
836 6 : case 'u': length = slprintf(buffer, 32, "%06d", (int) floor(t->f * 1000000)); break;
837 :
838 : /* timezone */
839 123 : case 'I': length = slprintf(buffer, 32, "%d", localtime ? offset->is_dst : 0); break;
840 24 : case 'P': rfc_colon = 1; /* break intentionally missing */
841 1055 : case 'O': length = slprintf(buffer, 32, "%c%02d%s%02d",
842 : localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
843 : localtime ? abs(offset->offset / 3600) : 0,
844 : rfc_colon ? ":" : "",
845 : localtime ? abs((offset->offset % 3600) / 60) : 0
846 : );
847 1055 : break;
848 251 : case 'T': length = slprintf(buffer, 32, "%s", localtime ? offset->abbr : "GMT"); break;
849 19 : case 'e': if (!localtime) {
850 4 : length = slprintf(buffer, 32, "%s", "UTC");
851 : } else {
852 15 : switch (t->zone_type) {
853 : case TIMELIB_ZONETYPE_ID:
854 11 : length = slprintf(buffer, 32, "%s", t->tz_info->name);
855 11 : break;
856 : case TIMELIB_ZONETYPE_ABBR:
857 0 : length = slprintf(buffer, 32, "%s", offset->abbr);
858 0 : break;
859 : case TIMELIB_ZONETYPE_OFFSET:
860 4 : length = slprintf(buffer, 32, "%c%02d:%02d",
861 : ((offset->offset < 0) ? '-' : '+'),
862 : abs(offset->offset / 3600),
863 : abs((offset->offset % 3600) / 60)
864 : );
865 : break;
866 : }
867 : }
868 19 : break;
869 5 : case 'Z': length = slprintf(buffer, 32, "%d", localtime ? offset->offset : 0); break;
870 :
871 : /* full date/time */
872 10 : case 'c': length = slprintf(buffer, 32, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
873 : (int) t->y, (int) t->m, (int) t->d,
874 : (int) t->h, (int) t->i, (int) t->s,
875 : localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
876 : localtime ? abs(offset->offset / 3600) : 0,
877 : localtime ? abs((offset->offset % 3600) / 60) : 0
878 : );
879 10 : break;
880 35 : case 'r': length = slprintf(buffer, 32, "%3s, %02d %3s %04d %02d:%02d:%02d %c%02d%02d",
881 : php_date_short_day_name(t->y, t->m, t->d),
882 : (int) t->d, mon_short_names[t->m - 1],
883 : (int) t->y, (int) t->h, (int) t->i, (int) t->s,
884 : localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
885 : localtime ? abs(offset->offset / 3600) : 0,
886 : localtime ? abs((offset->offset % 3600) / 60) : 0
887 : );
888 35 : break;
889 18 : case 'U': length = slprintf(buffer, 32, "%lld", (timelib_sll) t->sse); break;
890 :
891 1034 : case '\\': if (i < format_len) i++; /* break intentionally missing */
892 :
893 8944 : default: buffer[0] = format[i]; buffer[1] = '\0'; length = 1; break;
894 : }
895 22353 : smart_str_appendl(&string, buffer, length);
896 : }
897 :
898 3910 : smart_str_0(&string);
899 :
900 3910 : if (localtime) {
901 2997 : timelib_time_offset_dtor(offset);
902 : }
903 :
904 3910 : return string.c;
905 : }
906 :
907 : static void php_date(INTERNAL_FUNCTION_PARAMETERS, int localtime)
908 3032 : {
909 : char *format;
910 : int format_len;
911 : long ts;
912 : char *string;
913 :
914 3032 : if (ZEND_NUM_ARGS() == 1) {
915 95 : ts = time(NULL);
916 : }
917 3032 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &format, &format_len, &ts) == FAILURE) {
918 44 : RETURN_FALSE;
919 : }
920 :
921 2988 : string = php_format_date(format, format_len, ts, localtime TSRMLS_CC);
922 :
923 2988 : RETVAL_STRING(string, 0);
924 : }
925 : /* }}} */
926 :
927 : PHPAPI char *php_format_date(char *format, int format_len, time_t ts, int localtime TSRMLS_DC) /* {{{ */
928 3720 : {
929 : timelib_time *t;
930 : timelib_tzinfo *tzi;
931 : char *string;
932 :
933 3720 : t = timelib_time_ctor();
934 :
935 3720 : if (localtime) {
936 2791 : tzi = get_timezone_info(TSRMLS_C);
937 2791 : t->tz_info = tzi;
938 2791 : t->zone_type = TIMELIB_ZONETYPE_ID;
939 2791 : timelib_unixtime2local(t, ts);
940 : } else {
941 929 : tzi = NULL;
942 929 : timelib_unixtime2gmt(t, ts);
943 : }
944 :
945 3720 : string = date_format(format, format_len, t, localtime);
946 :
947 3720 : timelib_time_dtor(t);
948 3720 : return string;
949 : }
950 : /* }}} */
951 :
952 : /* {{{ php_idate
953 : */
954 : PHPAPI int php_idate(char format, time_t ts, int localtime)
955 83 : {
956 : timelib_time *t;
957 : timelib_tzinfo *tzi;
958 83 : int retval = -1;
959 83 : timelib_time_offset *offset = NULL;
960 : timelib_sll isoweek, isoyear;
961 :
962 83 : t = timelib_time_ctor();
963 :
964 83 : if (!localtime) {
965 : TSRMLS_FETCH();
966 83 : tzi = get_timezone_info(TSRMLS_C);
967 83 : t->tz_info = tzi;
968 83 : t->zone_type = TIMELIB_ZONETYPE_ID;
969 83 : timelib_unixtime2local(t, ts);
970 : } else {
971 0 : tzi = NULL;
972 0 : timelib_unixtime2gmt(t, ts);
973 : }
974 :
975 83 : if (!localtime) {
976 83 : if (t->zone_type == TIMELIB_ZONETYPE_ABBR) {
977 0 : offset = timelib_time_offset_ctor();
978 0 : offset->offset = (t->z - (t->dst * 60)) * -60;
979 0 : offset->leap_secs = 0;
980 0 : offset->is_dst = t->dst;
981 0 : offset->abbr = strdup(t->tz_abbr);
982 83 : } else if (t->zone_type == TIMELIB_ZONETYPE_OFFSET) {
983 0 : offset = timelib_time_offset_ctor();
984 0 : offset->offset = (t->z - (t->dst * 60)) * -60;
985 0 : offset->leap_secs = 0;
986 0 : offset->is_dst = t->dst;
987 0 : offset->abbr = malloc(9); /* GMT±xxxx\0 */
988 0 : snprintf(offset->abbr, 9, "GMT%c%02d%02d",
989 : !localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
990 : !localtime ? abs(offset->offset / 3600) : 0,
991 : !localtime ? abs((offset->offset % 3600) / 60) : 0 );
992 : } else {
993 83 : offset = timelib_get_time_zone_info(t->sse, t->tz_info);
994 : }
995 : }
996 :
997 83 : timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear);
998 :
999 83 : switch (format) {
1000 : /* day */
1001 4 : case 'd': case 'j': retval = (int) t->d; break;
1002 :
1003 3 : case 'w': retval = (int) timelib_day_of_week(t->y, t->m, t->d); break;
1004 3 : case 'z': retval = (int) timelib_day_of_year(t->y, t->m, t->d); break;
1005 :
1006 : /* week */
1007 3 : case 'W': retval = (int) isoweek; break; /* iso weeknr */
1008 :
1009 : /* month */
1010 4 : case 'm': case 'n': retval = (int) t->m; break;
1011 3 : case 't': retval = (int) timelib_days_in_month(t->y, t->m); break;
1012 :
1013 : /* year */
1014 3 : case 'L': retval = (int) timelib_is_leap((int) t->y); break;
1015 5 : case 'y': retval = (int) (t->y % 100); break;
1016 17 : case 'Y': retval = (int) t->y; break;
1017 :
1018 : /* Swatch Beat a.k.a. Internet Time */
1019 : case 'B':
1020 4 : retval = (((((long)t->sse)-(((long)t->sse) - ((((long)t->sse) % 86400) + 3600))) * 10) / 864);
1021 8 : while (retval < 0) {
1022 0 : retval += 1000;
1023 : }
1024 4 : retval = retval % 1000;
1025 4 : break;
1026 :
1027 : /* time */
1028 4 : case 'g': case 'h': retval = (int) ((t->h % 12) ? (int) t->h % 12 : 12); break;
1029 4 : case 'H': case 'G': retval = (int) t->h; break;
1030 3 : case 'i': retval = (int) t->i; break;
1031 3 : case 's': retval = (int) t->s; break;
1032 :
1033 : /* timezone */
1034 3 : case 'I': retval = (int) (!localtime ? offset->is_dst : 0); break;
1035 2 : case 'Z': retval = (int) (!localtime ? offset->offset : 0); break;
1036 :
1037 3 : case 'U': retval = (int) t->sse; break;
1038 : }
1039 :
1040 83 : if (!localtime) {
1041 83 : timelib_time_offset_dtor(offset);
1042 : }
1043 83 : timelib_time_dtor(t);
1044 :
1045 83 : return retval;
1046 : }
1047 : /* }}} */
1048 :
1049 : /* {{{ proto string date(string format [, long timestamp])
1050 : Format a local date/time */
1051 : PHP_FUNCTION(date)
1052 2811 : {
1053 2811 : php_date(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1054 2811 : }
1055 : /* }}} */
1056 :
1057 : /* {{{ proto string gmdate(string format [, long timestamp])
1058 : Format a GMT date/time */
1059 : PHP_FUNCTION(gmdate)
1060 221 : {
1061 221 : php_date(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1062 221 : }
1063 : /* }}} */
1064 :
1065 : /* {{{ proto int idate(string format [, int timestamp])
1066 : Format a local time/date as integer */
1067 : PHP_FUNCTION(idate)
1068 142 : {
1069 : char *format;
1070 : int format_len;
1071 : long ts;
1072 : int ret;
1073 :
1074 142 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &format, &format_len, &ts) == FAILURE) {
1075 26 : RETURN_FALSE;
1076 : }
1077 :
1078 116 : if (format_len != 1) {
1079 33 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "idate format is one char");
1080 33 : RETURN_FALSE;
1081 : }
1082 :
1083 83 : if (ZEND_NUM_ARGS() == 1) {
1084 24 : ts = time(NULL);
1085 : }
1086 :
1087 83 : ret = php_idate(format[0], ts, 0);
1088 83 : if (ret == -1) {
1089 12 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unrecognized date format token.");
1090 12 : RETURN_FALSE;
1091 : }
1092 71 : RETURN_LONG(ret);
1093 : }
1094 : /* }}} */
1095 :
1096 : /* {{{ php_date_set_tzdb - NOT THREADSAFE */
1097 : PHPAPI void php_date_set_tzdb(timelib_tzdb *tzdb)
1098 0 : {
1099 0 : const timelib_tzdb *builtin = timelib_builtin_db();
1100 :
1101 0 : if (php_version_compare(tzdb->version, builtin->version) > 0) {
1102 0 : php_date_global_timezone_db = tzdb;
1103 0 : php_date_global_timezone_db_enabled = 1;
1104 : }
1105 0 : }
1106 : /* }}} */
1107 :
1108 : /* {{{ php_parse_date: Backwards compability function */
1109 : PHPAPI signed long php_parse_date(char *string, signed long *now)
1110 12 : {
1111 : timelib_time *parsed_time;
1112 : int error2;
1113 : signed long retval;
1114 :
1115 12 : parsed_time = timelib_strtotime(string, strlen(string), NULL, DATE_TIMEZONEDB);
1116 12 : timelib_update_ts(parsed_time, NULL);
1117 12 : retval = timelib_date_to_int(parsed_time, &error2);
1118 12 : timelib_time_dtor(parsed_time);
1119 12 : if (error2) {
1120 2 : return -1;
1121 : }
1122 10 : return retval;
1123 : }
1124 : /* }}} */
1125 :
1126 :
1127 : /* {{{ proto int strtotime(string time [, int now ])
1128 : Convert string representation of date and time to a timestamp */
1129 : PHP_FUNCTION(strtotime)
1130 2618 : {
1131 : char *times, *initial_ts;
1132 : int time_len, error1, error2;
1133 : struct timelib_error_container *error;
1134 : long preset_ts, ts;
1135 :
1136 : timelib_time *t, *now;
1137 : timelib_tzinfo *tzi;
1138 :
1139 2618 : tzi = get_timezone_info(TSRMLS_C);
1140 :
1141 2618 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "sl", ×, &time_len, &preset_ts) != FAILURE) {
1142 : /* We have an initial timestamp */
1143 189 : now = timelib_time_ctor();
1144 :
1145 189 : initial_ts = emalloc(25);
1146 189 : snprintf(initial_ts, 24, "@%ld UTC", preset_ts);
1147 189 : t = timelib_strtotime(initial_ts, strlen(initial_ts), NULL, DATE_TIMEZONEDB); /* we ignore the error here, as this should never fail */
1148 189 : timelib_update_ts(t, tzi);
1149 189 : now->tz_info = tzi;
1150 189 : now->zone_type = TIMELIB_ZONETYPE_ID;
1151 189 : timelib_unixtime2local(now, t->sse);
1152 189 : timelib_time_dtor(t);
1153 189 : efree(initial_ts);
1154 2429 : } else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", ×, &time_len, &preset_ts) != FAILURE) {
1155 : /* We have no initial timestamp */
1156 2429 : now = timelib_time_ctor();
1157 2429 : now->tz_info = tzi;
1158 2429 : now->zone_type = TIMELIB_ZONETYPE_ID;
1159 2429 : timelib_unixtime2local(now, (timelib_sll) time(NULL));
1160 : } else {
1161 0 : RETURN_FALSE;
1162 : }
1163 :
1164 2618 : if (!time_len) {
1165 1 : timelib_time_dtor(now);
1166 1 : RETURN_FALSE;
1167 : }
1168 :
1169 2617 : t = timelib_strtotime(times, time_len, &error, DATE_TIMEZONEDB);
1170 2617 : error1 = error->error_count;
1171 2617 : timelib_error_container_dtor(error);
1172 2617 : timelib_fill_holes(t, now, TIMELIB_NO_CLONE);
1173 2617 : timelib_update_ts(t, tzi);
1174 2617 : ts = timelib_date_to_int(t, &error2);
1175 :
1176 2617 : timelib_time_dtor(now);
1177 2617 : timelib_time_dtor(t);
1178 :
1179 2617 : if (error1 || error2) {
1180 12 : RETURN_FALSE;
1181 : } else {
1182 2605 : RETURN_LONG(ts);
1183 : }
1184 : }
1185 : /* }}} */
1186 :
1187 :
1188 : /* {{{ php_mktime - (gm)mktime helper */
1189 : PHPAPI void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
1190 755 : {
1191 755 : long hou, min, sec, mon, day, yea, dst = -1;
1192 : timelib_time *now;
1193 755 : timelib_tzinfo *tzi = NULL;
1194 755 : long ts, adjust_seconds = 0;
1195 : int error;
1196 :
1197 755 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lllllll", &hou, &min, &sec, &mon, &day, &yea, &dst) == FAILURE) {
1198 165 : RETURN_FALSE;
1199 : }
1200 : /* Initialize structure with current time */
1201 590 : now = timelib_time_ctor();
1202 590 : if (gmt) {
1203 117 : timelib_unixtime2gmt(now, (timelib_sll) time(NULL));
1204 : } else {
1205 473 : tzi = get_timezone_info(TSRMLS_C);
1206 473 : now->tz_info = tzi;
1207 473 : now->zone_type = TIMELIB_ZONETYPE_ID;
1208 473 : timelib_unixtime2local(now, (timelib_sll) time(NULL));
1209 : }
1210 : /* Fill in the new data */
1211 590 : switch (ZEND_NUM_ARGS()) {
1212 : case 7:
1213 : /* break intentionally missing */
1214 : case 6:
1215 533 : if (yea >= 0 && yea < 70) {
1216 25 : yea += 2000;
1217 483 : } else if (yea >= 70 && yea <= 100) {
1218 8 : yea += 1900;
1219 : }
1220 508 : now->y = yea;
1221 : /* break intentionally missing again */
1222 : case 5:
1223 524 : now->d = day;
1224 : /* break missing intentionally here too */
1225 : case 4:
1226 540 : now->m = mon;
1227 : /* and here */
1228 : case 3:
1229 556 : now->s = sec;
1230 : /* yup, this break isn't here on purpose too */
1231 : case 2:
1232 572 : now->i = min;
1233 : /* last intentionally missing break */
1234 : case 1:
1235 588 : now->h = hou;
1236 588 : break;
1237 : default:
1238 2 : php_error_docref(NULL TSRMLS_CC, E_STRICT, "You should be using the time() function instead");
1239 : }
1240 : /* Update the timestamp */
1241 590 : if (gmt) {
1242 117 : timelib_update_ts(now, NULL);
1243 : } else {
1244 473 : timelib_update_ts(now, tzi);
1245 : }
1246 : /* Support for the deprecated is_dst parameter */
1247 590 : if (dst != -1) {
1248 39 : php_error_docref(NULL TSRMLS_CC, E_STRICT, "The is_dst parameter is deprecated");
1249 39 : if (gmt) {
1250 : /* GMT never uses DST */
1251 1 : if (dst == 1) {
1252 0 : adjust_seconds = -3600;
1253 : }
1254 : } else {
1255 : /* Figure out is_dst for current TS */
1256 : timelib_time_offset *tmp_offset;
1257 38 : tmp_offset = timelib_get_time_zone_info(now->sse, tzi);
1258 38 : if (dst == 1 && tmp_offset->is_dst == 0) {
1259 7 : adjust_seconds = -3600;
1260 : }
1261 38 : if (dst == 0 && tmp_offset->is_dst == 1) {
1262 13 : adjust_seconds = +3600;
1263 : }
1264 38 : timelib_time_offset_dtor(tmp_offset);
1265 : }
1266 : }
1267 : /* Clean up and return */
1268 590 : ts = timelib_date_to_int(now, &error);
1269 590 : ts += adjust_seconds;
1270 590 : timelib_time_dtor(now);
1271 :
1272 590 : if (error) {
1273 22 : RETURN_FALSE;
1274 : } else {
1275 568 : RETURN_LONG(ts);
1276 : }
1277 : }
1278 : /* }}} */
1279 :
1280 : /* {{{ proto int mktime([int hour [, int min [, int sec [, int mon [, int day [, int year]]]]]])
1281 : Get UNIX timestamp for a date */
1282 : PHP_FUNCTION(mktime)
1283 565 : {
1284 565 : php_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1285 565 : }
1286 : /* }}} */
1287 :
1288 : /* {{{ proto int gmmktime([int hour [, int min [, int sec [, int mon [, int day [, int year]]]]]])
1289 : Get UNIX timestamp for a GMT date */
1290 : PHP_FUNCTION(gmmktime)
1291 190 : {
1292 190 : php_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1293 190 : }
1294 : /* }}} */
1295 :
1296 :
1297 : /* {{{ proto bool checkdate(int month, int day, int year)
1298 : Returns true(1) if it is a valid date in gregorian calendar */
1299 : PHP_FUNCTION(checkdate)
1300 100 : {
1301 : long m, d, y;
1302 :
1303 100 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &m, &d, &y) == FAILURE) {
1304 45 : RETURN_FALSE;
1305 : }
1306 :
1307 55 : if (y < 1 || y > 32767 || m < 1 || m > 12 || d < 1 || d > timelib_days_in_month(y, m)) {
1308 36 : RETURN_FALSE;
1309 : }
1310 19 : RETURN_TRUE; /* True : This month, day, year arguments are valid */
1311 : }
1312 : /* }}} */
1313 :
1314 : #ifdef HAVE_STRFTIME
1315 : /* {{{ php_strftime - (gm)strftime helper */
1316 : PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
1317 383 : {
1318 : char *format, *buf;
1319 : int format_len;
1320 : long timestamp;
1321 : struct tm ta;
1322 383 : int max_reallocs = 5;
1323 383 : size_t buf_len = 64, real_len;
1324 : timelib_time *ts;
1325 : timelib_tzinfo *tzi;
1326 383 : timelib_time_offset *offset = NULL;
1327 :
1328 383 : timestamp = (long) time(NULL);
1329 :
1330 383 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &format, &format_len, ×tamp) == FAILURE) {
1331 49 : RETURN_FALSE;
1332 : }
1333 :
1334 334 : if (format_len == 0) {
1335 34 : RETURN_FALSE;
1336 : }
1337 :
1338 300 : ts = timelib_time_ctor();
1339 300 : if (gmt) {
1340 112 : tzi = NULL;
1341 112 : timelib_unixtime2gmt(ts, (timelib_sll) timestamp);
1342 : } else {
1343 188 : tzi = get_timezone_info(TSRMLS_C);
1344 188 : ts->tz_info = tzi;
1345 188 : ts->zone_type = TIMELIB_ZONETYPE_ID;
1346 188 : timelib_unixtime2local(ts, (timelib_sll) timestamp);
1347 : }
1348 300 : ta.tm_sec = ts->s;
1349 300 : ta.tm_min = ts->i;
1350 300 : ta.tm_hour = ts->h;
1351 300 : ta.tm_mday = ts->d;
1352 300 : ta.tm_mon = ts->m - 1;
1353 300 : ta.tm_year = ts->y - 1900;
1354 300 : ta.tm_wday = timelib_day_of_week(ts->y, ts->m, ts->d);
1355 300 : ta.tm_yday = timelib_day_of_year(ts->y, ts->m, ts->d);
1356 300 : if (gmt) {
1357 112 : ta.tm_isdst = 0;
1358 : #if HAVE_TM_GMTOFF
1359 112 : ta.tm_gmtoff = 0;
1360 : #endif
1361 : #if HAVE_TM_ZONE
1362 112 : ta.tm_zone = "GMT";
1363 : #endif
1364 : } else {
1365 188 : offset = timelib_get_time_zone_info(timestamp, tzi);
1366 :
1367 188 : ta.tm_isdst = offset->is_dst;
1368 : #if HAVE_TM_GMTOFF
1369 188 : ta.tm_gmtoff = offset->offset;
1370 : #endif
1371 : #if HAVE_TM_ZONE
1372 188 : ta.tm_zone = offset->abbr;
1373 : #endif
1374 : }
1375 :
1376 300 : buf = (char *) emalloc(buf_len);
1377 604 : while ((real_len=strftime(buf, buf_len, format, &ta))==buf_len || real_len==0) {
1378 4 : buf_len *= 2;
1379 4 : buf = (char *) erealloc(buf, buf_len);
1380 4 : if (!--max_reallocs) {
1381 0 : break;
1382 : }
1383 : }
1384 :
1385 300 : timelib_time_dtor(ts);
1386 300 : if (!gmt) {
1387 188 : timelib_time_offset_dtor(offset);
1388 : }
1389 :
1390 300 : if (real_len && real_len != buf_len) {
1391 300 : buf = (char *) erealloc(buf, real_len + 1);
1392 300 : RETURN_STRINGL(buf, real_len, 0);
1393 : }
1394 0 : efree(buf);
1395 0 : RETURN_FALSE;
1396 : }
1397 : /* }}} */
1398 :
1399 : /* {{{ proto string strftime(string format [, int timestamp])
1400 : Format a local time/date according to locale settings */
1401 : PHP_FUNCTION(strftime)
1402 229 : {
1403 229 : php_strftime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1404 229 : }
1405 : /* }}} */
1406 :
1407 : /* {{{ proto string gmstrftime(string format [, int timestamp])
1408 : Format a GMT/UCT time/date according to locale settings */
1409 : PHP_FUNCTION(gmstrftime)
1410 154 : {
1411 154 : php_strftime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1412 154 : }
1413 : /* }}} */
1414 : #endif
1415 :
1416 : /* {{{ proto int time(void)
1417 : Return current UNIX timestamp */
1418 : PHP_FUNCTION(time)
1419 21 : {
1420 21 : RETURN_LONG((long)time(NULL));
1421 : }
1422 : /* }}} */
1423 :
1424 : /* {{{ proto array localtime([int timestamp [, bool associative_array]])
1425 : 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 */
1426 : PHP_FUNCTION(localtime)
1427 100 : {
1428 100 : long timestamp = (long)time(NULL);
1429 100 : zend_bool associative = 0;
1430 : timelib_tzinfo *tzi;
1431 : timelib_time *ts;
1432 :
1433 100 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lb", ×tamp, &associative) == FAILURE) {
1434 32 : RETURN_FALSE;
1435 : }
1436 :
1437 68 : tzi = get_timezone_info(TSRMLS_C);
1438 68 : ts = timelib_time_ctor();
1439 68 : ts->tz_info = tzi;
1440 68 : ts->zone_type = TIMELIB_ZONETYPE_ID;
1441 68 : timelib_unixtime2local(ts, (timelib_sll) timestamp);
1442 :
1443 68 : array_init(return_value);
1444 :
1445 68 : if (associative) {
1446 35 : add_assoc_long(return_value, "tm_sec", ts->s);
1447 35 : add_assoc_long(return_value, "tm_min", ts->i);
1448 35 : add_assoc_long(return_value, "tm_hour", ts->h);
1449 35 : add_assoc_long(return_value, "tm_mday", ts->d);
1450 35 : add_assoc_long(return_value, "tm_mon", ts->m - 1);
1451 35 : add_assoc_long(return_value, "tm_year", ts->y - 1900);
1452 35 : add_assoc_long(return_value, "tm_wday", timelib_day_of_week(ts->y, ts->m, ts->d));
1453 35 : add_assoc_long(return_value, "tm_yday", timelib_day_of_year(ts->y, ts->m, ts->d));
1454 35 : add_assoc_long(return_value, "tm_isdst", ts->dst);
1455 : } else {
1456 33 : add_next_index_long(return_value, ts->s);
1457 33 : add_next_index_long(return_value, ts->i);
1458 33 : add_next_index_long(return_value, ts->h);
1459 33 : add_next_index_long(return_value, ts->d);
1460 33 : add_next_index_long(return_value, ts->m - 1);
1461 33 : add_next_index_long(return_value, ts->y- 1900);
1462 33 : add_next_index_long(return_value, timelib_day_of_week(ts->y, ts->m, ts->d));
1463 33 : add_next_index_long(return_value, timelib_day_of_year(ts->y, ts->m, ts->d));
1464 33 : add_next_index_long(return_value, ts->dst);
1465 : }
1466 :
1467 68 : timelib_time_dtor(ts);
1468 : }
1469 : /* }}} */
1470 :
1471 : /* {{{ proto array getdate([int timestamp])
1472 : Get date/time information */
1473 : PHP_FUNCTION(getdate)
1474 51 : {
1475 51 : long timestamp = (long)time(NULL);
1476 : timelib_tzinfo *tzi;
1477 : timelib_time *ts;
1478 :
1479 51 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", ×tamp) == FAILURE) {
1480 14 : RETURN_FALSE;
1481 : }
1482 :
1483 37 : tzi = get_timezone_info(TSRMLS_C);
1484 37 : ts = timelib_time_ctor();
1485 37 : ts->tz_info = tzi;
1486 37 : ts->zone_type = TIMELIB_ZONETYPE_ID;
1487 37 : timelib_unixtime2local(ts, (timelib_sll) timestamp);
1488 :
1489 37 : array_init(return_value);
1490 :
1491 37 : add_assoc_long(return_value, "seconds", ts->s);
1492 37 : add_assoc_long(return_value, "minutes", ts->i);
1493 37 : add_assoc_long(return_value, "hours", ts->h);
1494 37 : add_assoc_long(return_value, "mday", ts->d);
1495 37 : add_assoc_long(return_value, "wday", timelib_day_of_week(ts->y, ts->m, ts->d));
1496 37 : add_assoc_long(return_value, "mon", ts->m);
1497 37 : add_assoc_long(return_value, "year", ts->y);
1498 37 : add_assoc_long(return_value, "yday", timelib_day_of_year(ts->y, ts->m, ts->d));
1499 37 : add_assoc_string(return_value, "weekday", php_date_full_day_name(ts->y, ts->m, ts->d), 1);
1500 37 : add_assoc_string(return_value, "month", mon_full_names[ts->m - 1], 1);
1501 37 : add_index_long(return_value, 0, timestamp);
1502 :
1503 37 : timelib_time_dtor(ts);
1504 : }
1505 : /* }}} */
1506 :
1507 : static void date_register_classes(TSRMLS_D)
1508 13565 : {
1509 : zend_class_entry ce_date, ce_timezone;
1510 :
1511 13565 : INIT_CLASS_ENTRY(ce_date, "DateTime", date_funcs_date);
1512 13565 : ce_date.create_object = date_object_new_date;
1513 13565 : date_ce_date = zend_register_internal_class_ex(&ce_date, NULL, NULL TSRMLS_CC);
1514 13565 : memcpy(&date_object_handlers_date, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1515 13565 : date_object_handlers_date.clone_obj = date_object_clone_date;
1516 13565 : date_object_handlers_date.compare_objects = date_object_compare_date;
1517 :
1518 : #define REGISTER_DATE_CLASS_CONST_STRING(const_name, value) \
1519 : zend_declare_class_constant_stringl(date_ce_date, const_name, sizeof(const_name)-1, value, sizeof(value)-1 TSRMLS_CC);
1520 :
1521 13565 : REGISTER_DATE_CLASS_CONST_STRING("ATOM", DATE_FORMAT_RFC3339);
1522 13565 : REGISTER_DATE_CLASS_CONST_STRING("COOKIE", DATE_FORMAT_RFC850);
1523 13565 : REGISTER_DATE_CLASS_CONST_STRING("ISO8601", DATE_FORMAT_ISO8601);
1524 13565 : REGISTER_DATE_CLASS_CONST_STRING("RFC822", DATE_FORMAT_RFC822);
1525 13565 : REGISTER_DATE_CLASS_CONST_STRING("RFC850", DATE_FORMAT_RFC850);
1526 13565 : REGISTER_DATE_CLASS_CONST_STRING("RFC1036", DATE_FORMAT_RFC1036);
1527 13565 : REGISTER_DATE_CLASS_CONST_STRING("RFC1123", DATE_FORMAT_RFC1123);
1528 13565 : REGISTER_DATE_CLASS_CONST_STRING("RFC2822", DATE_FORMAT_RFC2822);
1529 13565 : REGISTER_DATE_CLASS_CONST_STRING("RFC3339", DATE_FORMAT_RFC3339);
1530 13565 : REGISTER_DATE_CLASS_CONST_STRING("RSS", DATE_FORMAT_RFC1123);
1531 13565 : REGISTER_DATE_CLASS_CONST_STRING("W3C", DATE_FORMAT_RFC3339);
1532 :
1533 :
1534 13565 : INIT_CLASS_ENTRY(ce_timezone, "DateTimeZone", date_funcs_timezone);
1535 13565 : ce_timezone.create_object = date_object_new_timezone;
1536 13565 : date_ce_timezone = zend_register_internal_class_ex(&ce_timezone, NULL, NULL TSRMLS_CC);
1537 13565 : memcpy(&date_object_handlers_timezone, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1538 13565 : date_object_handlers_timezone.clone_obj = date_object_clone_timezone;
1539 13565 : }
1540 :
1541 : static inline zend_object_value date_object_new_date_ex(zend_class_entry *class_type, php_date_obj **ptr TSRMLS_DC)
1542 327 : {
1543 : php_date_obj *intern;
1544 : zend_object_value retval;
1545 : zval *tmp;
1546 :
1547 327 : intern = emalloc(sizeof(php_date_obj));
1548 327 : memset(intern, 0, sizeof(php_date_obj));
1549 327 : if (ptr) {
1550 7 : *ptr = intern;
1551 : }
1552 :
1553 327 : zend_object_std_init(&intern->std, class_type TSRMLS_CC);
1554 327 : zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
1555 :
1556 327 : 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);
1557 327 : retval.handlers = &date_object_handlers_date;
1558 :
1559 327 : return retval;
1560 : }
1561 :
1562 : static zend_object_value date_object_new_date(zend_class_entry *class_type TSRMLS_DC)
1563 320 : {
1564 320 : return date_object_new_date_ex(class_type, NULL TSRMLS_CC);
1565 : }
1566 :
1567 : static zend_object_value date_object_clone_date(zval *this_ptr TSRMLS_DC)
1568 7 : {
1569 7 : php_date_obj *new_obj = NULL;
1570 7 : php_date_obj *old_obj = (php_date_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
1571 7 : zend_object_value new_ov = date_object_new_date_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
1572 :
1573 7 : zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
1574 :
1575 : /* this should probably moved to a new `timelib_time *timelime_time_clone(timelib_time *)` */
1576 7 : new_obj->time = timelib_time_ctor();
1577 7 : *new_obj->time = *old_obj->time;
1578 7 : if (old_obj->time->tz_abbr) {
1579 7 : new_obj->time->tz_abbr = strdup(old_obj->time->tz_abbr);
1580 : }
1581 7 : if (old_obj->time->tz_info) {
1582 7 : new_obj->time->tz_info = old_obj->time->tz_info;
1583 : }
1584 :
1585 7 : return new_ov;
1586 : }
1587 :
1588 : static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC)
1589 12 : {
1590 12 : if (Z_TYPE_P(d1) == IS_OBJECT && Z_TYPE_P(d2) == IS_OBJECT &&
1591 : instanceof_function(Z_OBJCE_P(d1), date_ce_date TSRMLS_CC) &&
1592 : instanceof_function(Z_OBJCE_P(d2), date_ce_date TSRMLS_CC)) {
1593 12 : php_date_obj *o1 = zend_object_store_get_object(d1 TSRMLS_CC);
1594 12 : php_date_obj *o2 = zend_object_store_get_object(d2 TSRMLS_CC);
1595 :
1596 12 : if (!o1->time->sse_uptodate) {
1597 0 : timelib_update_ts(o1->time, o1->time->tz_info);
1598 : }
1599 12 : if (!o2->time->sse_uptodate) {
1600 0 : timelib_update_ts(o2->time, o2->time->tz_info);
1601 : }
1602 :
1603 12 : return (o1->time->sse == o2->time->sse) ? 0 : ((o1->time->sse < o2->time->sse) ? -1 : 1);
1604 : }
1605 :
1606 0 : return 1;
1607 : }
1608 :
1609 : static inline zend_object_value date_object_new_timezone_ex(zend_class_entry *class_type, php_timezone_obj **ptr TSRMLS_DC)
1610 132 : {
1611 : php_timezone_obj *intern;
1612 : zend_object_value retval;
1613 : zval *tmp;
1614 :
1615 132 : intern = emalloc(sizeof(php_timezone_obj));
1616 132 : memset(intern, 0, sizeof(php_timezone_obj));
1617 132 : if (ptr) {
1618 7 : *ptr = intern;
1619 : }
1620 :
1621 132 : zend_object_std_init(&intern->std, class_type TSRMLS_CC);
1622 132 : zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
1623 :
1624 132 : 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);
1625 132 : retval.handlers = &date_object_handlers_timezone;
1626 :
1627 132 : return retval;
1628 : }
1629 :
1630 : static zend_object_value date_object_new_timezone(zend_class_entry *class_type TSRMLS_DC)
1631 125 : {
1632 125 : return date_object_new_timezone_ex(class_type, NULL TSRMLS_CC);
1633 : }
1634 :
1635 : static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC)
1636 7 : {
1637 7 : php_timezone_obj *new_obj = NULL;
1638 7 : php_timezone_obj *old_obj = (php_timezone_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
1639 7 : zend_object_value new_ov = date_object_new_timezone_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
1640 :
1641 7 : zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
1642 7 : new_obj->type = old_obj->type;
1643 7 : new_obj->initialized = 1;
1644 7 : switch (new_obj->type) {
1645 : case TIMELIB_ZONETYPE_ID:
1646 7 : new_obj->tzi.tz = old_obj->tzi.tz;
1647 7 : break;
1648 : case TIMELIB_ZONETYPE_OFFSET:
1649 0 : new_obj->tzi.utc_offset = old_obj->tzi.utc_offset;
1650 0 : break;
1651 : case TIMELIB_ZONETYPE_ABBR:
1652 0 : new_obj->tzi.z.utc_offset = old_obj->tzi.z.utc_offset;
1653 0 : new_obj->tzi.z.dst = old_obj->tzi.z.dst;
1654 0 : new_obj->tzi.z.abbr = old_obj->tzi.z.abbr;
1655 : break;
1656 : }
1657 :
1658 7 : return new_ov;
1659 : }
1660 :
1661 : static void date_object_free_storage_date(void *object TSRMLS_DC)
1662 327 : {
1663 327 : php_date_obj *intern = (php_date_obj *)object;
1664 :
1665 327 : if (intern->time) {
1666 284 : timelib_time_dtor(intern->time);
1667 : }
1668 :
1669 327 : zend_object_std_dtor(&intern->std TSRMLS_CC);
1670 327 : efree(object);
1671 327 : }
1672 :
1673 : static void date_object_free_storage_timezone(void *object TSRMLS_DC)
1674 132 : {
1675 132 : php_timezone_obj *intern = (php_timezone_obj *)object;
1676 :
1677 132 : if (intern->type == TIMELIB_ZONETYPE_ABBR) {
1678 2 : free(intern->tzi.z.abbr);
1679 : }
1680 132 : zend_object_std_dtor(&intern->std TSRMLS_CC);
1681 132 : efree(object);
1682 132 : }
1683 :
1684 : /* Advanced Interface */
1685 : static zval * date_instantiate(zend_class_entry *pce, zval *object TSRMLS_DC)
1686 214 : {
1687 214 : if (!object) {
1688 0 : ALLOC_ZVAL(object);
1689 : }
1690 :
1691 214 : Z_TYPE_P(object) = IS_OBJECT;
1692 214 : object_init_ex(object, pce);
1693 214 : object->refcount = 1;
1694 214 : object->is_ref = 0;
1695 214 : return object;
1696 : }
1697 :
1698 : static int date_initialize(php_date_obj *dateobj, /*const*/ char *time_str, int time_str_len, zval *timezone_object, int ctor TSRMLS_DC)
1699 277 : {
1700 : timelib_time *now;
1701 : timelib_tzinfo *tzi;
1702 277 : timelib_error_container *err = NULL;
1703 277 : int type = TIMELIB_ZONETYPE_ID, new_dst, errors_found = 0;
1704 : char *new_abbr;
1705 : timelib_sll new_offset;
1706 :
1707 277 : if (dateobj->time) {
1708 0 : timelib_time_dtor(dateobj->time);
1709 : }
1710 277 : dateobj->time = timelib_strtotime(time_str_len ? time_str : "now", time_str_len ? time_str_len : sizeof("now") -1, &err, DATE_TIMEZONEDB);
1711 :
1712 277 : if (err && err->error_count) {
1713 50 : if (ctor) {
1714 : /* spit out the first library error message, at least */
1715 25 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse time string (%s) at position %d (%c): %s", time_str,
1716 : err->error_messages[0].position, err->error_messages[0].character, err->error_messages[0].message);
1717 : }
1718 50 : errors_found = 1;
1719 : }
1720 277 : timelib_error_container_dtor(err);
1721 277 : if (errors_found) {
1722 50 : return 0;
1723 : }
1724 :
1725 227 : if (timezone_object) {
1726 : php_timezone_obj *tzobj;
1727 :
1728 33 : tzobj = (php_timezone_obj *) zend_object_store_get_object(timezone_object TSRMLS_CC);
1729 33 : switch (tzobj->type) {
1730 : case TIMELIB_ZONETYPE_ID:
1731 33 : tzi = tzobj->tzi.tz;
1732 33 : break;
1733 : case TIMELIB_ZONETYPE_OFFSET:
1734 0 : new_offset = tzobj->tzi.utc_offset;
1735 0 : break;
1736 : case TIMELIB_ZONETYPE_ABBR:
1737 0 : new_offset = tzobj->tzi.z.utc_offset;
1738 0 : new_dst = tzobj->tzi.z.dst;
1739 0 : new_abbr = strdup(tzobj->tzi.z.abbr);
1740 : break;
1741 : }
1742 33 : type = tzobj->type;
1743 194 : } else if (dateobj->time->tz_info) {
1744 7 : tzi = dateobj->time->tz_info;
1745 : } else {
1746 187 : tzi = get_timezone_info(TSRMLS_C);
1747 : }
1748 :
1749 227 : now = timelib_time_ctor();
1750 227 : now->zone_type = type;
1751 227 : switch (type) {
1752 : case TIMELIB_ZONETYPE_ID:
1753 227 : now->tz_info = tzi;
1754 227 : break;
1755 : case TIMELIB_ZONETYPE_OFFSET:
1756 0 : now->z = new_offset;
1757 0 : break;
1758 : case TIMELIB_ZONETYPE_ABBR:
1759 0 : now->z = new_offset;
1760 0 : now->dst = new_dst;
1761 0 : now->tz_abbr = new_abbr;
1762 : break;
1763 : }
1764 227 : timelib_unixtime2local(now, (timelib_sll) time(NULL));
1765 :
1766 227 : timelib_fill_holes(dateobj->time, now, TIMELIB_NO_CLONE);
1767 227 : timelib_update_ts(dateobj->time, tzi);
1768 :
1769 227 : dateobj->time->have_weekday_relative = dateobj->time->have_relative = 0;
1770 :
1771 227 : timelib_time_dtor(now);
1772 :
1773 227 : return 1;
1774 : }
1775 :
1776 : /* {{{ proto DateTime date_create([string time[, DateTimeZone object]])
1777 : Returns new DateTime object
1778 : */
1779 : PHP_FUNCTION(date_create)
1780 206 : {
1781 206 : zval *timezone_object = NULL;
1782 206 : char *time_str = NULL;
1783 206 : int time_str_len = 0;
1784 :
1785 206 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sO", &time_str, &time_str_len, &timezone_object, date_ce_timezone) == FAILURE) {
1786 42 : RETURN_FALSE;
1787 : }
1788 :
1789 164 : date_instantiate(date_ce_date, return_value TSRMLS_CC);
1790 164 : if (!date_initialize(zend_object_store_get_object(return_value TSRMLS_CC), time_str, time_str_len, timezone_object, 0 TSRMLS_CC)) {
1791 25 : RETURN_FALSE;
1792 : }
1793 : }
1794 : /* }}} */
1795 :
1796 : /* {{{ proto DateTime::__construct([string time[, DateTimeZone object]])
1797 : Creates new DateTime object
1798 : */
1799 : PHP_METHOD(DateTime, __construct)
1800 154 : {
1801 154 : zval *timezone_object = NULL;
1802 154 : char *time_str = NULL;
1803 154 : int time_str_len = 0;
1804 :
1805 154 : php_set_error_handling(EH_THROW, NULL TSRMLS_CC);
1806 154 : if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sO", &time_str, &time_str_len, &timezone_object, date_ce_timezone)) {
1807 113 : date_initialize(zend_object_store_get_object(getThis() TSRMLS_CC), time_str, time_str_len, timezone_object, 1 TSRMLS_CC);
1808 : }
1809 154 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
1810 154 : }
1811 : /* }}} */
1812 :
1813 : /* {{{ proto array date_parse(string date)
1814 : Returns associative array with detailed info about given date
1815 : */
1816 : PHP_FUNCTION(date_parse)
1817 55 : {
1818 : char *date;
1819 : int date_len, i;
1820 : struct timelib_error_container *error;
1821 : timelib_time *parsed_time;
1822 : zval *element;
1823 :
1824 55 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &date, &date_len) == FAILURE) {
1825 9 : RETURN_FALSE;
1826 : }
1827 :
1828 46 : parsed_time = timelib_strtotime(date, date_len, &error, DATE_TIMEZONEDB);
1829 46 : array_init(return_value);
1830 : #define PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(name, elem) \
1831 : if (parsed_time->elem == -99999) { \
1832 : add_assoc_bool(return_value, #name, 0); \
1833 : } else { \
1834 : add_assoc_long(return_value, #name, parsed_time->elem); \
1835 : }
1836 46 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(year, y);
1837 46 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(month, m);
1838 46 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(day, d);
1839 46 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(hour, h);
1840 46 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(minute, i);
1841 46 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(second, s);
1842 :
1843 46 : if (parsed_time->f == -99999) {
1844 38 : add_assoc_bool(return_value, "fraction", 0);
1845 : } else {
1846 8 : add_assoc_double(return_value, "fraction", parsed_time->f);
1847 : }
1848 :
1849 46 : add_assoc_long(return_value, "warning_count", error->warning_count);
1850 46 : MAKE_STD_ZVAL(element);
1851 46 : array_init(element);
1852 61 : for (i = 0; i < error->warning_count; i++) {
1853 15 : add_index_string(element, error->warning_messages[i].position, error->warning_messages[i].message, 1);
1854 : }
1855 46 : add_assoc_zval(return_value, "warnings", element);
1856 :
1857 46 : add_assoc_long(return_value, "error_count", error->error_count);
1858 46 : MAKE_STD_ZVAL(element);
1859 46 : array_init(element);
1860 79 : for (i = 0; i < error->error_count; i++) {
1861 33 : add_index_string(element, error->error_messages[i].position, error->error_messages[i].message, 1);
1862 : }
1863 46 : add_assoc_zval(return_value, "errors", element);
1864 46 : timelib_error_container_dtor(error);
1865 :
1866 46 : add_assoc_bool(return_value, "is_localtime", parsed_time->is_localtime);
1867 :
1868 46 : if (parsed_time->is_localtime) {
1869 19 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone_type, zone_type);
1870 19 : switch (parsed_time->zone_type) {
1871 : case TIMELIB_ZONETYPE_OFFSET:
1872 5 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone, z);
1873 5 : add_assoc_bool(return_value, "is_dst", parsed_time->dst);
1874 5 : break;
1875 : case TIMELIB_ZONETYPE_ID:
1876 0 : if (parsed_time->tz_abbr) {
1877 0 : add_assoc_string(return_value, "tz_abbr", parsed_time->tz_abbr, 1);
1878 : }
1879 0 : if (parsed_time->tz_info) {
1880 0 : add_assoc_string(return_value, "tz_id", parsed_time->tz_info->name, 1);
1881 : }
1882 0 : break;
1883 : case TIMELIB_ZONETYPE_ABBR:
1884 7 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone, z);
1885 7 : add_assoc_bool(return_value, "is_dst", parsed_time->dst);
1886 7 : add_assoc_string(return_value, "tz_abbr", parsed_time->tz_abbr, 1);
1887 : break;
1888 : }
1889 : }
1890 46 : if (parsed_time->have_relative || parsed_time->have_weekday_relative) {
1891 0 : MAKE_STD_ZVAL(element);
1892 0 : array_init(element);
1893 : }
1894 46 : if (parsed_time->have_relative) {
1895 0 : add_assoc_long(element, "year", parsed_time->relative.y);
1896 0 : add_assoc_long(element, "month", parsed_time->relative.m);
1897 0 : add_assoc_long(element, "day", parsed_time->relative.d);
1898 0 : add_assoc_long(element, "hour", parsed_time->relative.h);
1899 0 : add_assoc_long(element, "minute", parsed_time->relative.i);
1900 0 : add_assoc_long(element, "second", parsed_time->relative.s);
1901 : }
1902 46 : if (parsed_time->have_weekday_relative) {
1903 0 : add_assoc_long(element, "weekday", parsed_time->relative.weekday);
1904 : }
1905 46 : if (parsed_time->have_relative || parsed_time->have_weekday_relative) {
1906 0 : add_assoc_zval(return_value, "relative", element);
1907 : }
1908 46 : timelib_time_dtor(parsed_time);
1909 : }
1910 : /* }}} */
1911 :
1912 : /* {{{ proto string date_format(DateTime object, string format)
1913 : Returns date formatted according to given format
1914 : */
1915 : PHP_FUNCTION(date_format)
1916 281 : {
1917 : zval *object;
1918 : php_date_obj *dateobj;
1919 : char *format;
1920 : int format_len;
1921 :
1922 281 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_date, &format, &format_len) == FAILURE) {
1923 48 : RETURN_FALSE;
1924 : }
1925 233 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
1926 233 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
1927 231 : RETURN_STRING(date_format(format, format_len, dateobj->time, dateobj->time->is_localtime), 0);
1928 : }
1929 : /* }}} */
1930 :
1931 : /* {{{ proto void date_modify(DateTime object, string modify)
1932 : Alters the timestamp.
1933 : */
1934 : PHP_FUNCTION(date_modify)
1935 115 : {
1936 : zval *object;
1937 : php_date_obj *dateobj;
1938 : char *modify;
1939 : int modify_len;
1940 : timelib_time *tmp_time;
1941 :
1942 115 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_date, &modify, &modify_len) == FAILURE) {
1943 48 : RETURN_FALSE;
1944 : }
1945 67 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
1946 67 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
1947 :
1948 67 : tmp_time = timelib_strtotime(modify, modify_len, NULL, DATE_TIMEZONEDB);
1949 67 : memcpy(&dateobj->time->relative, &tmp_time->relative, sizeof(struct timelib_rel_time));
1950 67 : dateobj->time->have_relative = tmp_time->have_relative;
1951 67 : dateobj->time->have_weekday_relative = tmp_time->have_weekday_relative;
1952 67 : dateobj->time->sse_uptodate = 0;
1953 67 : timelib_time_dtor(tmp_time);
1954 :
1955 67 : timelib_update_ts(dateobj->time, NULL);
1956 67 : timelib_update_from_sse(dateobj->time);
1957 : }
1958 : /* }}} */
1959 :
1960 : /* {{{ proto DateTimeZone date_timezone_get(DateTime object)
1961 : Return new DateTimeZone object relative to give DateTime
1962 : */
1963 : PHP_FUNCTION(date_timezone_get)
1964 65 : {
1965 : zval *object;
1966 : php_date_obj *dateobj;
1967 : php_timezone_obj *tzobj;
1968 :
1969 65 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_date) == FAILURE) {
1970 33 : RETURN_FALSE;
1971 : }
1972 32 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
1973 32 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
1974 32 : if (dateobj->time->is_localtime/* && dateobj->time->tz_info*/) {
1975 32 : date_instantiate(date_ce_timezone, return_value TSRMLS_CC);
1976 32 : tzobj = (php_timezone_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
1977 32 : tzobj->initialized = 1;
1978 32 : tzobj->type = dateobj->time->zone_type;
1979 32 : switch (dateobj->time->zone_type) {
1980 : case TIMELIB_ZONETYPE_ID:
1981 20 : tzobj->tzi.tz = dateobj->time->tz_info;
1982 20 : break;
1983 : case TIMELIB_ZONETYPE_OFFSET:
1984 10 : tzobj->tzi.utc_offset = dateobj->time->z;
1985 10 : break;
1986 : case TIMELIB_ZONETYPE_ABBR:
1987 2 : tzobj->tzi.z.utc_offset = dateobj->time->z;
1988 2 : tzobj->tzi.z.dst = dateobj->time->dst;
1989 2 : tzobj->tzi.z.abbr = strdup(dateobj->time->tz_abbr);
1990 : break;
1991 : }
1992 : } else {
1993 0 : RETURN_FALSE;
1994 : }
1995 : }
1996 : /* }}} */
1997 :
1998 : /* {{{ proto void date_timezone_set(DateTime object, DateTimeZone object)
1999 : Sets the timezone for the DateTime object.
2000 : */
2001 : PHP_FUNCTION(date_timezone_set)
2002 101 : {
2003 : zval *object;
2004 : zval *timezone_object;
2005 : php_date_obj *dateobj;
2006 : php_timezone_obj *tzobj;
2007 :
2008 101 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &timezone_object, date_ce_timezone) == FAILURE) {
2009 92 : RETURN_FALSE;
2010 : }
2011 9 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
2012 9 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
2013 9 : tzobj = (php_timezone_obj *) zend_object_store_get_object(timezone_object TSRMLS_CC);
2014 9 : if (tzobj->type != TIMELIB_ZONETYPE_ID) {
2015 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can only do this for zones with ID for now");
2016 0 : return;
2017 : }
2018 9 : timelib_set_timezone(dateobj->time, tzobj->tzi.tz);
2019 9 : timelib_unixtime2local(dateobj->time, dateobj->time->sse);
2020 : }
2021 : /* }}} */
2022 :
2023 : /* {{{ proto long date_offset_get(DateTime object)
2024 : Returns the DST offset.
2025 : */
2026 : PHP_FUNCTION(date_offset_get)
2027 38 : {
2028 : zval *object;
2029 : php_date_obj *dateobj;
2030 : timelib_time_offset *offset;
2031 :
2032 38 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_date) == FAILURE) {
2033 34 : RETURN_FALSE;
2034 : }
2035 4 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
2036 4 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
2037 4 : if (dateobj->time->is_localtime/* && dateobj->time->tz_info*/) {
2038 4 : switch (dateobj->time->zone_type) {
2039 : case TIMELIB_ZONETYPE_ID:
2040 4 : offset = timelib_get_time_zone_info(dateobj->time->sse, dateobj->time->tz_info);
2041 4 : RETVAL_LONG(offset->offset);
2042 4 : timelib_time_offset_dtor(offset);
2043 4 : break;
2044 : case TIMELIB_ZONETYPE_OFFSET:
2045 0 : RETVAL_LONG(dateobj->time->z * -60);
2046 0 : break;
2047 : case TIMELIB_ZONETYPE_ABBR:
2048 0 : RETVAL_LONG((dateobj->time->z - (60 * dateobj->time->dst)) * -60);
2049 : break;
2050 : }
2051 4 : return;
2052 : } else {
2053 0 : RETURN_LONG(0);
2054 : }
2055 : }
2056 : /* }}} */
2057 :
2058 : /* {{{ proto void date_time_set(DateTime object, long hour, long minute[, long second])
2059 : Sets the time.
2060 : */
2061 : PHP_FUNCTION(date_time_set)
2062 223 : {
2063 : zval *object;
2064 : php_date_obj *dateobj;
2065 223 : long h, i, s = 0;
2066 :
2067 223 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_date, &h, &i, &s) == FAILURE) {
2068 116 : RETURN_FALSE;
2069 : }
2070 107 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
2071 107 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
2072 107 : dateobj->time->h = h;
2073 107 : dateobj->time->i = i;
2074 107 : dateobj->time->s = s;
2075 107 : timelib_update_ts(dateobj->time, NULL);
2076 : }
2077 : /* }}} */
2078 :
2079 : /* {{{ proto void date_date_set(DateTime object, long year, long month, long day)
2080 : Sets the date.
2081 : */
2082 : PHP_FUNCTION(date_date_set)
2083 214 : {
2084 : zval *object;
2085 : php_date_obj *dateobj;
2086 : long y, m, d;
2087 :
2088 214 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Olll", &object, date_ce_date, &y, &m, &d) == FAILURE) {
2089 117 : RETURN_FALSE;
2090 : }
2091 97 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
2092 97 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
2093 97 : dateobj->time->y = y;
2094 97 : dateobj->time->m = m;
2095 97 : dateobj->time->d = d;
2096 97 : timelib_update_ts(dateobj->time, NULL);
2097 : }
2098 : /* }}} */
2099 :
2100 : /* {{{ proto void date_isodate_set(DateTime object, long year, long week[, long day])
2101 : Sets the ISO date.
2102 : */
2103 : PHP_FUNCTION(date_isodate_set)
2104 216 : {
2105 : zval *object;
2106 : php_date_obj *dateobj;
2107 216 : long y, w, d = 1;
2108 :
2109 216 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_date, &y, &w, &d) == FAILURE) {
2110 117 : RETURN_FALSE;
2111 : }
2112 99 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
2113 99 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
2114 99 : dateobj->time->y = y;
2115 99 : dateobj->time->m = 1;
2116 99 : dateobj->time->d = 1;
2117 99 : dateobj->time->relative.d = timelib_daynr_from_weeknr(y, w, d);
2118 99 : dateobj->time->have_relative = 1;
2119 :
2120 99 : timelib_update_ts(dateobj->time, NULL);
2121 : }
2122 : /* }}} */
2123 :
2124 : static int timezone_initialize(timelib_tzinfo **tzi, /*const*/ char *tz TSRMLS_DC)
2125 106 : {
2126 : char *tzid;
2127 :
2128 106 : *tzi = NULL;
2129 :
2130 106 : if ((tzid = timelib_timezone_id_from_abbr(tz, -1, 0))) {
2131 10 : *tzi = php_date_parse_tzfile(tzid, DATE_TIMEZONEDB TSRMLS_CC);
2132 : } else {
2133 96 : *tzi = php_date_parse_tzfile(tz, DATE_TIMEZONEDB TSRMLS_CC);
2134 : }
2135 :
2136 106 : if (*tzi) {
2137 61 : return SUCCESS;
2138 : } else {
2139 45 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or bad timezone (%s)", tz);
2140 45 : return FAILURE;
2141 : }
2142 : }
2143 :
2144 : /* {{{ proto DateTimeZone timezone_open(string timezone)
2145 : Returns new DateTimeZone object
2146 : */
2147 : PHP_FUNCTION(timezone_open)
2148 48 : {
2149 : char *tz;
2150 : int tz_len;
2151 48 : timelib_tzinfo *tzi = NULL;
2152 : php_timezone_obj *tzobj;
2153 :
2154 48 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &tz, &tz_len) == FAILURE) {
2155 8 : RETURN_FALSE;
2156 : }
2157 40 : if (SUCCESS != timezone_initialize(&tzi, tz TSRMLS_CC)) {
2158 22 : RETURN_FALSE;
2159 : }
2160 18 : tzobj = zend_object_store_get_object(date_instantiate(date_ce_timezone, return_value TSRMLS_CC) TSRMLS_CC);
2161 18 : tzobj->type = TIMELIB_ZONETYPE_ID;
2162 18 : tzobj->tzi.tz = tzi;
2163 18 : tzobj->initialized = 1;
2164 : }
2165 : /* }}} */
2166 :
2167 : /* {{{ proto DateTimeZone::__construct(string timezone)
2168 : Creates new DateTimeZone object.
2169 : */
2170 : PHP_METHOD(DateTimeZone, __construct)
2171 73 : {
2172 : char *tz;
2173 : int tz_len;
2174 73 : timelib_tzinfo *tzi = NULL;
2175 : php_timezone_obj *tzobj;
2176 :
2177 73 : php_set_error_handling(EH_THROW, NULL TSRMLS_CC);
2178 73 : if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &tz, &tz_len)) {
2179 66 : if (SUCCESS == timezone_initialize(&tzi, tz TSRMLS_CC)) {
2180 43 : tzobj = zend_object_store_get_object(getThis() TSRMLS_CC);
2181 43 : tzobj->type = TIMELIB_ZONETYPE_ID;
2182 43 : tzobj->tzi.tz = tzi;
2183 43 : tzobj->initialized = 1;
2184 : } else {
2185 23 : ZVAL_NULL(getThis());
2186 : }
2187 : }
2188 73 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
2189 73 : }
2190 : /* }}} */
2191 :
2192 : /* {{{ proto string timezone_name_get(DateTimeZone object)
2193 : Returns the name of the timezone.
2194 : */
2195 : PHP_FUNCTION(timezone_name_get)
2196 36 : {
2197 : zval *object;
2198 : php_timezone_obj *tzobj;
2199 :
2200 36 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_timezone) == FAILURE) {
2201 6 : RETURN_FALSE;
2202 : }
2203 30 : tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
2204 30 : DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
2205 :
2206 28 : switch (tzobj->type) {
2207 : case TIMELIB_ZONETYPE_ID:
2208 23 : RETURN_STRING(tzobj->tzi.tz->name, 1);
2209 : break;
2210 : case TIMELIB_ZONETYPE_OFFSET: {
2211 5 : char *tmpstr = emalloc(sizeof("UTC+05:00"));
2212 5 : timelib_sll utc_offset = tzobj->tzi.utc_offset;
2213 :
2214 5 : snprintf(tmpstr, sizeof("+05:00"), "%c%02d:%02d",
2215 : utc_offset > 0 ? '-' : '+',
2216 : abs(utc_offset / 60),
2217 : abs((utc_offset % 60)));
2218 :
2219 5 : RETURN_STRING(tmpstr, 0);
2220 : }
2221 : break;
2222 : case TIMELIB_ZONETYPE_ABBR:
2223 0 : RETURN_STRING(tzobj->tzi.z.abbr, 1);
2224 : break;
2225 : }
2226 : }
2227 : /* }}} */
2228 :
2229 : /* {{{ proto string timezone_name_from_abbr(string abbr[, long gmtOffset[, long isdst]])
2230 : Returns the timezone name from abbrevation
2231 : */
2232 : PHP_FUNCTION(timezone_name_from_abbr)
2233 105 : {
2234 : char *abbr;
2235 : char *tzid;
2236 : int abbr_len;
2237 105 : long gmtoffset = -1;
2238 105 : long isdst = -1;
2239 :
2240 105 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ll", &abbr, &abbr_len, &gmtoffset, &isdst) == FAILURE) {
2241 35 : RETURN_FALSE;
2242 : }
2243 70 : tzid = timelib_timezone_id_from_abbr(abbr, gmtoffset, isdst);
2244 :
2245 70 : if (tzid) {
2246 66 : RETURN_STRING(tzid, 1);
2247 : } else {
2248 4 : RETURN_FALSE;
2249 : }
2250 : }
2251 : /* }}} */
2252 :
2253 : /* {{{ proto long timezone_offset_get(DateTimeZone object, DateTime object)
2254 : Returns the timezone offset.
2255 : */
2256 : PHP_FUNCTION(timezone_offset_get)
2257 115 : {
2258 : zval *object, *dateobject;
2259 : php_timezone_obj *tzobj;
2260 : php_date_obj *dateobj;
2261 : timelib_time_offset *offset;
2262 :
2263 115 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_timezone, &dateobject, date_ce_date) == FAILURE) {
2264 97 : RETURN_FALSE;
2265 : }
2266 18 : tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
2267 18 : DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
2268 18 : dateobj = (php_date_obj *) zend_object_store_get_object(dateobject TSRMLS_CC);
2269 18 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
2270 :
2271 18 : switch (tzobj->type) {
2272 : case TIMELIB_ZONETYPE_ID:
2273 11 : offset = timelib_get_time_zone_info(dateobj->time->sse, tzobj->tzi.tz);
2274 11 : RETVAL_LONG(offset->offset);
2275 11 : timelib_time_offset_dtor(offset);
2276 11 : break;
2277 : case TIMELIB_ZONETYPE_OFFSET:
2278 5 : RETURN_LONG(tzobj->tzi.utc_offset * -60);
2279 : break;
2280 : case TIMELIB_ZONETYPE_ABBR:
2281 2 : RETURN_LONG((tzobj->tzi.z.utc_offset - (tzobj->tzi.z.dst*60)) * -60);
2282 : break;
2283 : }
2284 : }
2285 : /* }}} */
2286 :
2287 : /* {{{ proto array timezone_transitions_get(DateTimeZone object)
2288 : Returns numeracilly indexed array containing associative array for all transitions for the timezone.
2289 : */
2290 : PHP_FUNCTION(timezone_transitions_get)
2291 37 : {
2292 : zval *object, *element;
2293 : php_timezone_obj *tzobj;
2294 : unsigned int i;
2295 :
2296 37 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_timezone) == FAILURE) {
2297 34 : RETURN_FALSE;
2298 : }
2299 3 : tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
2300 3 : DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
2301 3 : if (tzobj->type != TIMELIB_ZONETYPE_ID) {
2302 0 : RETURN_FALSE;
2303 : }
2304 :
2305 3 : array_init(return_value);
2306 729 : for (i = 0; i < tzobj->tzi.tz->timecnt; ++i) {
2307 726 : MAKE_STD_ZVAL(element);
2308 726 : array_init(element);
2309 726 : add_assoc_long(element, "ts", tzobj->tzi.tz->trans[i]);
2310 726 : add_assoc_string(element, "time", php_format_date(DATE_FORMAT_ISO8601, 13, tzobj->tzi.tz->trans[i], 0 TSRMLS_CC), 0);
2311 726 : add_assoc_long(element, "offset", tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].offset);
2312 726 : add_assoc_bool(element, "isdst", tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].isdst);
2313 726 : add_assoc_string(element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].abbr_idx], 1);
2314 :
2315 726 : add_next_index_zval(return_value, element);
2316 : }
2317 : }
2318 : /* }}} */
2319 :
2320 : /* {{{ proto array timezone_identifiers_list()
2321 : Returns numerically index array with all timezone identifiers.
2322 : */
2323 : PHP_FUNCTION(timezone_identifiers_list)
2324 2 : {
2325 : const timelib_tzdb *tzdb;
2326 : const timelib_tzdb_index_entry *table;
2327 : int i, item_count;
2328 :
2329 2 : tzdb = DATE_TIMEZONEDB;
2330 2 : item_count = tzdb->index_size;
2331 2 : table = tzdb->index;
2332 :
2333 2 : array_init(return_value);
2334 :
2335 1124 : for (i = 0; i < item_count; ++i) {
2336 1122 : add_next_index_string(return_value, table[i].id, 1);
2337 : };
2338 2 : }
2339 : /* }}} */
2340 :
2341 : /* {{{ proto array timezone_abbreviations_list()
2342 : Returns associative array containing dst, offset and the timezone name
2343 : */
2344 : PHP_FUNCTION(timezone_abbreviations_list)
2345 3 : {
2346 : const timelib_tz_lookup_table *table, *entry;
2347 : zval *element, **abbr_array_pp, *abbr_array;
2348 :
2349 3 : table = timelib_timezone_abbreviations_list();
2350 3 : array_init(return_value);
2351 3 : entry = table;
2352 :
2353 : do {
2354 5094 : MAKE_STD_ZVAL(element);
2355 5094 : array_init(element);
2356 5094 : add_assoc_bool(element, "dst", entry->type);
2357 5094 : add_assoc_long(element, "offset", entry->gmtoffset);
2358 5094 : if (entry->full_tz_name) {
2359 5019 : add_assoc_string(element, "timezone_id", entry->full_tz_name, 1);
2360 : } else {
2361 75 : add_assoc_null(element, "timezone_id");
2362 : }
2363 :
2364 5094 : if (zend_hash_find(HASH_OF(return_value), entry->name, strlen(entry->name) + 1, (void **) &abbr_array_pp) == FAILURE) {
2365 1014 : MAKE_STD_ZVAL(abbr_array);
2366 1014 : array_init(abbr_array);
2367 1014 : add_assoc_zval(return_value, entry->name, abbr_array);
2368 : } else {
2369 4080 : abbr_array = *abbr_array_pp;
2370 : }
2371 5094 : add_next_index_zval(abbr_array, element);
2372 5094 : entry++;
2373 5094 : } while (entry->name);
2374 3 : }
2375 : /* }}} */
2376 :
2377 : /* {{{ proto bool date_default_timezone_set(string timezone_identifier)
2378 : Sets the default timezone used by all date/time functions in a script */
2379 : PHP_FUNCTION(date_default_timezone_set)
2380 365 : {
2381 : char *zone;
2382 : int zone_len;
2383 :
2384 365 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &zone, &zone_len) == FAILURE) {
2385 4 : RETURN_FALSE;
2386 : }
2387 361 : if (!timelib_timezone_id_is_valid(zone, DATE_TIMEZONEDB)) {
2388 25 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Timezone ID '%s' is invalid", zone);
2389 25 : RETURN_FALSE;
2390 : }
2391 336 : if (DATEG(timezone)) {
2392 33 : efree(DATEG(timezone));
2393 33 : DATEG(timezone) = NULL;
2394 : }
2395 336 : DATEG(timezone) = estrndup(zone, zone_len);
2396 336 : RETURN_TRUE;
2397 : }
2398 : /* }}} */
2399 :
2400 : /* {{{ proto string date_default_timezone_get()
2401 : Gets the default timezone used by all date/time functions in a script */
2402 : PHP_FUNCTION(date_default_timezone_get)
2403 11 : {
2404 : timelib_tzinfo *default_tz;
2405 :
2406 11 : default_tz = get_timezone_info(TSRMLS_C);
2407 11 : RETVAL_STRING(default_tz->name, 1);
2408 11 : }
2409 : /* }}} */
2410 :
2411 : /* {{{ php_do_date_sunrise_sunset
2412 : * Common for date_sunrise() and date_sunset() functions
2413 : */
2414 : static void php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAMETERS, int calc_sunset)
2415 952 : {
2416 952 : double latitude, longitude, zenith, gmt_offset = 0, altitude;
2417 : double h_rise, h_set, N;
2418 : timelib_sll rise, set, transit;
2419 : long time, retformat;
2420 : int rs;
2421 : timelib_time *t;
2422 : timelib_tzinfo *tzi;
2423 : char *retstr;
2424 :
2425 952 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|ldddd", &time, &retformat, &latitude, &longitude, &zenith, &gmt_offset) == FAILURE) {
2426 390 : RETURN_FALSE;
2427 : }
2428 :
2429 562 : switch (ZEND_NUM_ARGS()) {
2430 : case 1:
2431 0 : retformat = SUNFUNCS_RET_STRING;
2432 : case 2:
2433 0 : latitude = INI_FLT("date.default_latitude");
2434 : case 3:
2435 0 : longitude = INI_FLT("date.default_longitude");
2436 : case 4:
2437 36 : if (calc_sunset) {
2438 12 : zenith = INI_FLT("date.sunset_zenith");
2439 : } else {
2440 24 : zenith = INI_FLT("date.sunrise_zenith");
2441 : }
2442 : case 5:
2443 : case 6:
2444 : break;
2445 : default:
2446 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid format");
2447 0 : RETURN_FALSE;
2448 : break;
2449 : }
2450 944 : if (retformat != SUNFUNCS_RET_TIMESTAMP &&
2451 : retformat != SUNFUNCS_RET_STRING &&
2452 : retformat != SUNFUNCS_RET_DOUBLE)
2453 : {
2454 8 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Wrong return format given, pick one of SUNFUNCS_RET_TIMESTAMP, SUNFUNCS_RET_STRING or SUNFUNCS_RET_DOUBLE");
2455 8 : RETURN_FALSE;
2456 : }
2457 554 : altitude = 90 - zenith;
2458 :
2459 : /* Initialize time struct */
2460 554 : t = timelib_time_ctor();
2461 554 : tzi = get_timezone_info(TSRMLS_C);
2462 554 : t->tz_info = tzi;
2463 554 : t->zone_type = TIMELIB_ZONETYPE_ID;
2464 :
2465 554 : if (ZEND_NUM_ARGS() <= 5) {
2466 36 : gmt_offset = timelib_get_current_offset(t) / 3600;
2467 : }
2468 :
2469 554 : timelib_unixtime2local(t, time);
2470 554 : rs = timelib_astro_rise_set_altitude(t, longitude, latitude, altitude, 1, &h_rise, &h_set, &rise, &set, &transit);
2471 554 : timelib_time_dtor(t);
2472 :
2473 554 : if (rs != 0) {
2474 108 : RETURN_FALSE;
2475 : }
2476 :
2477 446 : if (retformat == SUNFUNCS_RET_TIMESTAMP) {
2478 144 : RETURN_LONG(calc_sunset ? set : rise);
2479 : }
2480 302 : N = (calc_sunset ? h_set : h_rise) + gmt_offset;
2481 :
2482 302 : if (N > 24 || N < 0) {
2483 28 : N -= floor(N / 24) * 24;
2484 : }
2485 :
2486 302 : switch (retformat) {
2487 : case SUNFUNCS_RET_STRING:
2488 172 : spprintf(&retstr, 0, "%02d:%02d", (int) N, (int) (60 * (N - (int) N)));
2489 172 : RETURN_STRINGL(retstr, 5, 0);
2490 : break;
2491 : case SUNFUNCS_RET_DOUBLE:
2492 130 : RETURN_DOUBLE(N);
2493 : break;
2494 : }
2495 : }
2496 : /* }}} */
2497 :
2498 : /* {{{ proto mixed date_sunrise(mixed time [, int format [, float latitude [, float longitude [, float zenith [, float gmt_offset]]]]])
2499 : Returns time of sunrise for a given day and location */
2500 : PHP_FUNCTION(date_sunrise)
2501 481 : {
2502 481 : php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2503 481 : }
2504 : /* }}} */
2505 :
2506 : /* {{{ proto mixed date_sunset(mixed time [, int format [, float latitude [, float longitude [, float zenith [, float gmt_offset]]]]])
2507 : Returns time of sunset for a given day and location */
2508 : PHP_FUNCTION(date_sunset)
2509 471 : {
2510 471 : php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
2511 471 : }
2512 : /* }}} */
2513 :
2514 : /* {{{ proto array date_sun_info(long time, float latitude, float longitude)
2515 : Returns an array with information about sun set/rise and twilight begin/end */
2516 : PHP_FUNCTION(date_sun_info)
2517 77 : {
2518 : long time;
2519 : double latitude, longitude;
2520 : timelib_time *t, *t2;
2521 : timelib_tzinfo *tzi;
2522 : int rs;
2523 : timelib_sll rise, set, transit;
2524 : int dummy;
2525 : double ddummy;
2526 :
2527 77 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ldd", &time, &latitude, &longitude) == FAILURE) {
2528 24 : RETURN_FALSE;
2529 : }
2530 : /* Initialize time struct */
2531 53 : t = timelib_time_ctor();
2532 53 : tzi = get_timezone_info(TSRMLS_C);
2533 53 : t->tz_info = tzi;
2534 53 : t->zone_type = TIMELIB_ZONETYPE_ID;
2535 53 : timelib_unixtime2local(t, time);
2536 :
2537 : /* Setup */
2538 53 : t2 = timelib_time_ctor();
2539 53 : array_init(return_value);
2540 :
2541 : /* Get sun up/down and transit */
2542 53 : rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -35.0/60, 1, &ddummy, &ddummy, &rise, &set, &transit);
2543 53 : switch (rs) {
2544 : case -1: /* always below */
2545 0 : add_assoc_bool(return_value, "sunrise", 0);
2546 0 : add_assoc_bool(return_value, "sunset", 0);
2547 0 : break;
2548 : case 1: /* always above */
2549 1 : add_assoc_bool(return_value, "sunrise", 1);
2550 1 : add_assoc_bool(return_value, "sunset", 1);
2551 1 : break;
2552 : default:
2553 52 : t2->sse = rise;
2554 52 : add_assoc_long(return_value, "sunrise", timelib_date_to_int(t2, &dummy));
2555 52 : t2->sse = set;
2556 52 : add_assoc_long(return_value, "sunset", timelib_date_to_int(t2, &dummy));
2557 : }
2558 53 : t2->sse = transit;
2559 53 : add_assoc_long(return_value, "transit", timelib_date_to_int(t2, &dummy));
2560 :
2561 : /* Get civil twilight */
2562 53 : rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -6.0, 0, &ddummy, &ddummy, &rise, &set, &transit);
2563 53 : switch (rs) {
2564 : case -1: /* always below */
2565 0 : add_assoc_bool(return_value, "civil_twilight_begin", 0);
2566 0 : add_assoc_bool(return_value, "civil_twilight_end", 0);
2567 0 : break;
2568 : case 1: /* always above */
2569 1 : add_assoc_bool(return_value, "civil_twilight_begin", 1);
2570 1 : add_assoc_bool(return_value, "civil_twilight_end", 1);
2571 1 : break;
2572 : default:
2573 52 : t2->sse = rise;
2574 52 : add_assoc_long(return_value, "civil_twilight_begin", timelib_date_to_int(t2, &dummy));
2575 52 : t2->sse = set;
2576 52 : add_assoc_long(return_value, "civil_twilight_end", timelib_date_to_int(t2, &dummy));
2577 : }
2578 :
2579 : /* Get nautical twilight */
2580 53 : rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -12.0, 0, &ddummy, &ddummy, &rise, &set, &transit);
2581 53 : switch (rs) {
2582 : case -1: /* always below */
2583 0 : add_assoc_bool(return_value, "nautical_twilight_begin", 0);
2584 0 : add_assoc_bool(return_value, "nautical_twilight_end", 0);
2585 0 : break;
2586 : case 1: /* always above */
2587 0 : add_assoc_bool(return_value, "nautical_twilight_begin", 1);
2588 0 : add_assoc_bool(return_value, "nautical_twilight_end", 1);
2589 0 : break;
2590 : default:
2591 53 : t2->sse = rise;
2592 53 : add_assoc_long(return_value, "nautical_twilight_begin", timelib_date_to_int(t2, &dummy));
2593 53 : t2->sse = set;
2594 53 : add_assoc_long(return_value, "nautical_twilight_end", timelib_date_to_int(t2, &dummy));
2595 : }
2596 :
2597 : /* Get astronomical twilight */
2598 53 : rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -18.0, 0, &ddummy, &ddummy, &rise, &set, &transit);
2599 53 : switch (rs) {
2600 : case -1: /* always below */
2601 0 : add_assoc_bool(return_value, "astronomical_twilight_begin", 0);
2602 0 : add_assoc_bool(return_value, "astronomical_twilight_end", 0);
2603 0 : break;
2604 : case 1: /* always above */
2605 0 : add_assoc_bool(return_value, "astronomical_twilight_begin", 1);
2606 0 : add_assoc_bool(return_value, "astronomical_twilight_end", 1);
2607 0 : break;
2608 : default:
2609 53 : t2->sse = rise;
2610 53 : add_assoc_long(return_value, "astronomical_twilight_begin", timelib_date_to_int(t2, &dummy));
2611 53 : t2->sse = set;
2612 53 : add_assoc_long(return_value, "astronomical_twilight_end", timelib_date_to_int(t2, &dummy));
2613 : }
2614 53 : timelib_time_dtor(t);
2615 53 : timelib_time_dtor(t2);
2616 : }
2617 : /* }}} */
2618 : /*
2619 : * Local variables:
2620 : * tab-width: 4
2621 : * c-basic-offset: 4
2622 : * End:
2623 : * vim600: fdm=marker
2624 : * vim: noet sw=4 ts=4
2625 : */
|