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