Back to index

php5  5.3.10
php_date.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Derick Rethans <derick@derickrethans.nl>                    |
00016    +----------------------------------------------------------------------+
00017  */
00018 
00019 /* $Id: php_date.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #include "php.h"
00022 #include "php_streams.h"
00023 #include "php_main.h"
00024 #include "php_globals.h"
00025 #include "php_ini.h"
00026 #include "ext/standard/info.h"
00027 #include "ext/standard/php_versioning.h"
00028 #include "ext/standard/php_math.h"
00029 #include "php_date.h"
00030 #include "zend_interfaces.h"
00031 #include "lib/timelib.h"
00032 #include <time.h>
00033 
00034 #ifdef PHP_WIN32
00035 static __inline __int64 php_date_llabs( __int64 i ) { return i >= 0? i: -i; }
00036 #elif defined(__GNUC__) && __GNUC__ < 3
00037 static __inline __int64_t php_date_llabs( __int64_t i ) { return i >= 0 ? i : -i; }
00038 #else
00039 static inline long long php_date_llabs( long long i ) { return i >= 0 ? i : -i; }
00040 #endif
00041 
00042 /* {{{ arginfo */
00043 ZEND_BEGIN_ARG_INFO_EX(arginfo_date, 0, 0, 1)
00044        ZEND_ARG_INFO(0, format)
00045        ZEND_ARG_INFO(0, timestamp)
00046 ZEND_END_ARG_INFO()
00047 
00048 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmdate, 0, 0, 1)
00049        ZEND_ARG_INFO(0, format)
00050        ZEND_ARG_INFO(0, timestamp)
00051 ZEND_END_ARG_INFO()
00052 
00053 ZEND_BEGIN_ARG_INFO_EX(arginfo_idate, 0, 0, 1)
00054        ZEND_ARG_INFO(0, format)
00055        ZEND_ARG_INFO(0, timestamp)
00056 ZEND_END_ARG_INFO()
00057 
00058 ZEND_BEGIN_ARG_INFO_EX(arginfo_strtotime, 0, 0, 1)
00059        ZEND_ARG_INFO(0, time)
00060        ZEND_ARG_INFO(0, now)
00061 ZEND_END_ARG_INFO()
00062 
00063 ZEND_BEGIN_ARG_INFO_EX(arginfo_mktime, 0, 0, 0)
00064        ZEND_ARG_INFO(0, hour)
00065        ZEND_ARG_INFO(0, min)
00066        ZEND_ARG_INFO(0, sec)
00067        ZEND_ARG_INFO(0, mon)
00068        ZEND_ARG_INFO(0, day)
00069        ZEND_ARG_INFO(0, year)
00070 ZEND_END_ARG_INFO()
00071 
00072 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmmktime, 0, 0, 0)
00073        ZEND_ARG_INFO(0, hour)
00074        ZEND_ARG_INFO(0, min)
00075        ZEND_ARG_INFO(0, sec)
00076        ZEND_ARG_INFO(0, mon)
00077        ZEND_ARG_INFO(0, day)
00078        ZEND_ARG_INFO(0, year)
00079 ZEND_END_ARG_INFO()
00080 
00081 ZEND_BEGIN_ARG_INFO(arginfo_checkdate, 0)
00082        ZEND_ARG_INFO(0, month)
00083        ZEND_ARG_INFO(0, day)
00084        ZEND_ARG_INFO(0, year)
00085 ZEND_END_ARG_INFO()
00086 
00087 ZEND_BEGIN_ARG_INFO_EX(arginfo_strftime, 0, 0, 1)
00088        ZEND_ARG_INFO(0, format)
00089        ZEND_ARG_INFO(0, timestamp)
00090 ZEND_END_ARG_INFO()
00091 
00092 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmstrftime, 0, 0, 1)
00093        ZEND_ARG_INFO(0, format)
00094        ZEND_ARG_INFO(0, timestamp)
00095 ZEND_END_ARG_INFO()
00096 
00097 ZEND_BEGIN_ARG_INFO(arginfo_time, 0)
00098 ZEND_END_ARG_INFO()
00099 
00100 ZEND_BEGIN_ARG_INFO_EX(arginfo_localtime, 0, 0, 0)
00101        ZEND_ARG_INFO(0, timestamp)
00102        ZEND_ARG_INFO(0, associative_array)
00103 ZEND_END_ARG_INFO()
00104 
00105 ZEND_BEGIN_ARG_INFO_EX(arginfo_getdate, 0, 0, 0)
00106        ZEND_ARG_INFO(0, timestamp)
00107 ZEND_END_ARG_INFO()
00108 
00109 ZEND_BEGIN_ARG_INFO(arginfo_date_default_timezone_set, 0)
00110        ZEND_ARG_INFO(0, timezone_identifier)
00111 ZEND_END_ARG_INFO()
00112 
00113 ZEND_BEGIN_ARG_INFO(arginfo_date_default_timezone_get, 0)
00114 ZEND_END_ARG_INFO()
00115 
00116 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_sunrise, 0, 0, 1)
00117        ZEND_ARG_INFO(0, time)
00118        ZEND_ARG_INFO(0, format)
00119        ZEND_ARG_INFO(0, latitude)
00120        ZEND_ARG_INFO(0, longitude)
00121        ZEND_ARG_INFO(0, zenith)
00122        ZEND_ARG_INFO(0, gmt_offset)
00123 ZEND_END_ARG_INFO()
00124 
00125 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_sunset, 0, 0, 1)
00126        ZEND_ARG_INFO(0, time)
00127        ZEND_ARG_INFO(0, format)
00128        ZEND_ARG_INFO(0, latitude)
00129        ZEND_ARG_INFO(0, longitude)
00130        ZEND_ARG_INFO(0, zenith)
00131        ZEND_ARG_INFO(0, gmt_offset)
00132 ZEND_END_ARG_INFO()
00133 
00134 ZEND_BEGIN_ARG_INFO(arginfo_date_sun_info, 0)
00135        ZEND_ARG_INFO(0, time)
00136        ZEND_ARG_INFO(0, latitude)
00137        ZEND_ARG_INFO(0, longitude)
00138 ZEND_END_ARG_INFO()
00139 
00140 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_create, 0, 0, 0)
00141        ZEND_ARG_INFO(0, time)
00142        ZEND_ARG_INFO(0, object)
00143 ZEND_END_ARG_INFO()
00144 
00145 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_create_from_format, 0, 0, 2)
00146        ZEND_ARG_INFO(0, format)
00147        ZEND_ARG_INFO(0, time)
00148        ZEND_ARG_INFO(0, object)
00149 ZEND_END_ARG_INFO()
00150 
00151 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_parse, 0, 0, 1)
00152        ZEND_ARG_INFO(0, date)
00153 ZEND_END_ARG_INFO()
00154 
00155 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_parse_from_format, 0, 0, 2)
00156        ZEND_ARG_INFO(0, format)
00157        ZEND_ARG_INFO(0, date)
00158 ZEND_END_ARG_INFO()
00159 
00160 ZEND_BEGIN_ARG_INFO(arginfo_date_get_last_errors, 0)
00161 ZEND_END_ARG_INFO()
00162 
00163 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_format, 0, 0, 2)
00164        ZEND_ARG_INFO(0, object)
00165        ZEND_ARG_INFO(0, format)
00166 ZEND_END_ARG_INFO()
00167 
00168 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_format, 0, 0, 1)
00169        ZEND_ARG_INFO(0, format)
00170 ZEND_END_ARG_INFO()
00171 
00172 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_modify, 0, 0, 2)
00173        ZEND_ARG_INFO(0, object)
00174        ZEND_ARG_INFO(0, modify)
00175 ZEND_END_ARG_INFO()
00176 
00177 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_modify, 0, 0, 1)
00178        ZEND_ARG_INFO(0, modify)
00179 ZEND_END_ARG_INFO()
00180 
00181 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_add, 0, 0, 2)
00182        ZEND_ARG_INFO(0, object)
00183        ZEND_ARG_INFO(0, interval)
00184 ZEND_END_ARG_INFO()
00185 
00186 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_add, 0, 0, 1)
00187        ZEND_ARG_INFO(0, interval)
00188 ZEND_END_ARG_INFO()
00189 
00190 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_sub, 0, 0, 2)
00191        ZEND_ARG_INFO(0, object)
00192        ZEND_ARG_INFO(0, interval)
00193 ZEND_END_ARG_INFO()
00194 
00195 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_sub, 0, 0, 1)
00196        ZEND_ARG_INFO(0, interval)
00197 ZEND_END_ARG_INFO()
00198 
00199 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timezone_get, 0, 0, 1)
00200        ZEND_ARG_INFO(0, object)
00201 ZEND_END_ARG_INFO()
00202 
00203 ZEND_BEGIN_ARG_INFO(arginfo_date_method_timezone_get, 0)
00204 ZEND_END_ARG_INFO()
00205 
00206 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timezone_set, 0, 0, 2)
00207        ZEND_ARG_INFO(0, object)
00208        ZEND_ARG_INFO(0, timezone)
00209 ZEND_END_ARG_INFO()
00210 
00211 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_timezone_set, 0, 0, 1)
00212        ZEND_ARG_INFO(0, timezone)
00213 ZEND_END_ARG_INFO()
00214 
00215 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_offset_get, 0, 0, 1)
00216        ZEND_ARG_INFO(0, object)
00217 ZEND_END_ARG_INFO()
00218 
00219 ZEND_BEGIN_ARG_INFO(arginfo_date_method_offset_get, 0)
00220 ZEND_END_ARG_INFO()
00221 
00222 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_diff, 0, 0, 2)
00223        ZEND_ARG_INFO(0, object)
00224        ZEND_ARG_INFO(0, object2)
00225        ZEND_ARG_INFO(0, absolute)
00226 ZEND_END_ARG_INFO()
00227 
00228 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_diff, 0, 0, 1)
00229        ZEND_ARG_INFO(0, object)
00230        ZEND_ARG_INFO(0, absolute)
00231 ZEND_END_ARG_INFO()
00232 
00233 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_time_set, 0, 0, 3)
00234        ZEND_ARG_INFO(0, object)
00235        ZEND_ARG_INFO(0, hour)
00236        ZEND_ARG_INFO(0, minute)
00237        ZEND_ARG_INFO(0, second)
00238 ZEND_END_ARG_INFO()
00239 
00240 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_time_set, 0, 0, 2)
00241        ZEND_ARG_INFO(0, hour)
00242        ZEND_ARG_INFO(0, minute)
00243        ZEND_ARG_INFO(0, second)
00244 ZEND_END_ARG_INFO()
00245 
00246 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_date_set, 0, 0, 4)
00247        ZEND_ARG_INFO(0, object)
00248        ZEND_ARG_INFO(0, year)
00249        ZEND_ARG_INFO(0, month)
00250        ZEND_ARG_INFO(0, day)
00251 ZEND_END_ARG_INFO()
00252 
00253 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_date_set, 0, 0, 3)
00254        ZEND_ARG_INFO(0, year)
00255        ZEND_ARG_INFO(0, month)
00256        ZEND_ARG_INFO(0, day)
00257 ZEND_END_ARG_INFO()
00258 
00259 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_isodate_set, 0, 0, 3)
00260        ZEND_ARG_INFO(0, object)
00261        ZEND_ARG_INFO(0, year)
00262        ZEND_ARG_INFO(0, week)
00263        ZEND_ARG_INFO(0, day)
00264 ZEND_END_ARG_INFO()
00265 
00266 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_isodate_set, 0, 0, 2)
00267        ZEND_ARG_INFO(0, year)
00268        ZEND_ARG_INFO(0, week)
00269        ZEND_ARG_INFO(0, day)
00270 ZEND_END_ARG_INFO()
00271 
00272 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timestamp_set, 0, 0, 2)
00273        ZEND_ARG_INFO(0, object)
00274        ZEND_ARG_INFO(0, unixtimestamp)
00275 ZEND_END_ARG_INFO()
00276 
00277 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_timestamp_set, 0, 0, 1)
00278        ZEND_ARG_INFO(0, unixtimestamp)
00279 ZEND_END_ARG_INFO()
00280 
00281 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timestamp_get, 0, 0, 1)
00282        ZEND_ARG_INFO(0, object)
00283 ZEND_END_ARG_INFO()
00284 
00285 ZEND_BEGIN_ARG_INFO(arginfo_date_method_timestamp_get, 0)
00286 ZEND_END_ARG_INFO()
00287 
00288 ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_open, 0, 0, 1)
00289        ZEND_ARG_INFO(0, timezone)
00290 ZEND_END_ARG_INFO()
00291 
00292 ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_name_get, 0, 0, 1)
00293        ZEND_ARG_INFO(0, object)
00294 ZEND_END_ARG_INFO()
00295 
00296 ZEND_BEGIN_ARG_INFO(arginfo_timezone_method_name_get, 0)
00297 ZEND_END_ARG_INFO()
00298 
00299 ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_name_from_abbr, 0, 0, 1)
00300        ZEND_ARG_INFO(0, abbr)
00301        ZEND_ARG_INFO(0, gmtoffset)
00302        ZEND_ARG_INFO(0, isdst)
00303 ZEND_END_ARG_INFO()
00304 
00305 ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_offset_get, 0, 0, 2)
00306        ZEND_ARG_INFO(0, object)
00307        ZEND_ARG_INFO(0, datetime)
00308 ZEND_END_ARG_INFO()
00309 
00310 ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_method_offset_get, 0, 0, 1)
00311        ZEND_ARG_INFO(0, datetime)
00312 ZEND_END_ARG_INFO()
00313 
00314 ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_transitions_get, 0, 0, 1)
00315        ZEND_ARG_INFO(0, object)
00316        ZEND_ARG_INFO(0, timestamp_begin)
00317        ZEND_ARG_INFO(0, timestamp_end)
00318 ZEND_END_ARG_INFO()
00319 
00320 ZEND_BEGIN_ARG_INFO(arginfo_timezone_method_transitions_get, 0)
00321        ZEND_ARG_INFO(0, timestamp_begin)
00322        ZEND_ARG_INFO(0, timestamp_end)
00323 ZEND_END_ARG_INFO()
00324 
00325 ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_location_get, 0, 0, 1)
00326        ZEND_ARG_INFO(0, object)
00327 ZEND_END_ARG_INFO()
00328 
00329 ZEND_BEGIN_ARG_INFO(arginfo_timezone_method_location_get, 0)
00330 ZEND_END_ARG_INFO()
00331 
00332 ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_identifiers_list, 0, 0, 0)
00333        ZEND_ARG_INFO(0, what)
00334        ZEND_ARG_INFO(0, country)
00335 ZEND_END_ARG_INFO()
00336 
00337 ZEND_BEGIN_ARG_INFO(arginfo_timezone_abbreviations_list, 0)
00338 ZEND_END_ARG_INFO()
00339 
00340 ZEND_BEGIN_ARG_INFO(arginfo_timezone_version_get, 0)
00341 ZEND_END_ARG_INFO()
00342 
00343 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_create_from_date_string, 0, 0, 1)
00344        ZEND_ARG_INFO(0, time)
00345 ZEND_END_ARG_INFO()
00346 
00347 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_format, 0, 0, 2)
00348        ZEND_ARG_INFO(0, object)
00349        ZEND_ARG_INFO(0, format)
00350 ZEND_END_ARG_INFO()
00351 
00352 ZEND_BEGIN_ARG_INFO(arginfo_date_method_interval_format, 0)
00353        ZEND_ARG_INFO(0, format)
00354 ZEND_END_ARG_INFO()
00355 
00356 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_period_construct, 0, 0, 3)
00357        ZEND_ARG_INFO(0, start)
00358        ZEND_ARG_INFO(0, interval)
00359        ZEND_ARG_INFO(0, end)
00360 ZEND_END_ARG_INFO()
00361 
00362 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_construct, 0, 0, 0)
00363        ZEND_ARG_INFO(0, interval_spec)
00364 ZEND_END_ARG_INFO()
00365 /* }}} */
00366 
00367 /* {{{ Function table */
00368 const zend_function_entry date_functions[] = {
00369        PHP_FE(strtotime, arginfo_strtotime)
00370        PHP_FE(date, arginfo_date)
00371        PHP_FE(idate, arginfo_idate)
00372        PHP_FE(gmdate, arginfo_gmdate)
00373        PHP_FE(mktime, arginfo_mktime)
00374        PHP_FE(gmmktime, arginfo_gmmktime)
00375        PHP_FE(checkdate, arginfo_checkdate)
00376 
00377 #ifdef HAVE_STRFTIME
00378        PHP_FE(strftime, arginfo_strftime)
00379        PHP_FE(gmstrftime, arginfo_gmstrftime)
00380 #endif
00381 
00382        PHP_FE(time, arginfo_time)
00383        PHP_FE(localtime, arginfo_localtime)
00384        PHP_FE(getdate, arginfo_getdate)
00385 
00386        /* Advanced Interface */
00387        PHP_FE(date_create, arginfo_date_create)
00388        PHP_FE(date_create_from_format, arginfo_date_create_from_format)
00389        PHP_FE(date_parse, arginfo_date_parse)
00390        PHP_FE(date_parse_from_format, arginfo_date_parse_from_format)
00391        PHP_FE(date_get_last_errors, arginfo_date_get_last_errors)
00392        PHP_FE(date_format, arginfo_date_format)
00393        PHP_FE(date_modify, arginfo_date_modify)
00394        PHP_FE(date_add, arginfo_date_add)
00395        PHP_FE(date_sub, arginfo_date_sub)
00396        PHP_FE(date_timezone_get, arginfo_date_timezone_get)
00397        PHP_FE(date_timezone_set, arginfo_date_timezone_set)
00398        PHP_FE(date_offset_get, arginfo_date_offset_get)
00399        PHP_FE(date_diff, arginfo_date_diff)
00400 
00401        PHP_FE(date_time_set, arginfo_date_time_set)
00402        PHP_FE(date_date_set, arginfo_date_date_set)
00403        PHP_FE(date_isodate_set, arginfo_date_isodate_set)
00404        PHP_FE(date_timestamp_set, arginfo_date_timestamp_set)
00405        PHP_FE(date_timestamp_get, arginfo_date_timestamp_get)
00406 
00407        PHP_FE(timezone_open, arginfo_timezone_open)
00408        PHP_FE(timezone_name_get, arginfo_timezone_name_get)
00409        PHP_FE(timezone_name_from_abbr, arginfo_timezone_name_from_abbr)
00410        PHP_FE(timezone_offset_get, arginfo_timezone_offset_get)
00411        PHP_FE(timezone_transitions_get, arginfo_timezone_transitions_get)
00412        PHP_FE(timezone_location_get, arginfo_timezone_location_get)
00413        PHP_FE(timezone_identifiers_list, arginfo_timezone_identifiers_list)
00414        PHP_FE(timezone_abbreviations_list, arginfo_timezone_abbreviations_list)
00415        PHP_FE(timezone_version_get, arginfo_timezone_version_get)
00416 
00417        PHP_FE(date_interval_create_from_date_string, arginfo_date_interval_create_from_date_string)
00418        PHP_FE(date_interval_format, arginfo_date_interval_format)
00419 
00420        /* Options and Configuration */
00421        PHP_FE(date_default_timezone_set, arginfo_date_default_timezone_set)
00422        PHP_FE(date_default_timezone_get, arginfo_date_default_timezone_get)
00423 
00424        /* Astronomical functions */
00425        PHP_FE(date_sunrise, arginfo_date_sunrise)
00426        PHP_FE(date_sunset, arginfo_date_sunset)
00427        PHP_FE(date_sun_info, arginfo_date_sun_info)
00428        PHP_FE_END
00429 };
00430 
00431 const zend_function_entry date_funcs_date[] = {
00432        PHP_ME(DateTime,                   __construct,         arginfo_date_create, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
00433        PHP_ME(DateTime,                   __wakeup,                   NULL, ZEND_ACC_PUBLIC)
00434        PHP_ME(DateTime,                   __set_state,         NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
00435        PHP_ME_MAPPING(createFromFormat, date_create_from_format,      arginfo_date_create_from_format, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
00436        PHP_ME_MAPPING(getLastErrors, date_get_last_errors,     arginfo_date_get_last_errors, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
00437        PHP_ME_MAPPING(format,             date_format,         arginfo_date_method_format, 0)
00438        PHP_ME_MAPPING(modify,             date_modify,         arginfo_date_method_modify, 0)
00439        PHP_ME_MAPPING(add,                date_add,                   arginfo_date_method_add, 0)
00440        PHP_ME_MAPPING(sub,                date_sub,                   arginfo_date_method_sub, 0)
00441        PHP_ME_MAPPING(getTimezone, date_timezone_get,   arginfo_date_method_timezone_get, 0)
00442        PHP_ME_MAPPING(setTimezone, date_timezone_set,   arginfo_date_method_timezone_set, 0)
00443        PHP_ME_MAPPING(getOffset,   date_offset_get,     arginfo_date_method_offset_get, 0)
00444        PHP_ME_MAPPING(setTime,            date_time_set,              arginfo_date_method_time_set, 0)
00445        PHP_ME_MAPPING(setDate,            date_date_set,              arginfo_date_method_date_set, 0)
00446        PHP_ME_MAPPING(setISODate,  date_isodate_set,    arginfo_date_method_isodate_set, 0)
00447        PHP_ME_MAPPING(setTimestamp,       date_timestamp_set, arginfo_date_method_timestamp_set, 0)
00448        PHP_ME_MAPPING(getTimestamp,       date_timestamp_get, arginfo_date_method_timestamp_get, 0)
00449        PHP_ME_MAPPING(diff,               date_diff, arginfo_date_method_diff, 0)
00450        PHP_FE_END
00451 };
00452 
00453 const zend_function_entry date_funcs_timezone[] = {
00454        PHP_ME(DateTimeZone,              __construct,                 arginfo_timezone_open, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
00455        PHP_ME_MAPPING(getName,           timezone_name_get,           arginfo_timezone_method_name_get, 0)
00456        PHP_ME_MAPPING(getOffset,         timezone_offset_get,         arginfo_timezone_method_offset_get, 0)
00457        PHP_ME_MAPPING(getTransitions,    timezone_transitions_get,    arginfo_timezone_method_transitions_get, 0)
00458        PHP_ME_MAPPING(getLocation,       timezone_location_get,       arginfo_timezone_method_location_get, 0)
00459        PHP_ME_MAPPING(listAbbreviations, timezone_abbreviations_list, arginfo_timezone_abbreviations_list, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
00460        PHP_ME_MAPPING(listIdentifiers,   timezone_identifiers_list,   arginfo_timezone_identifiers_list, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
00461        PHP_FE_END
00462 };
00463 
00464 const zend_function_entry date_funcs_interval[] = {
00465        PHP_ME(DateInterval,              __construct,                 arginfo_date_interval_construct, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
00466        PHP_ME(DateInterval,              __wakeup,                    NULL, ZEND_ACC_PUBLIC)
00467        PHP_ME(DateInterval,              __set_state,                 NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
00468        PHP_ME_MAPPING(format,            date_interval_format,        arginfo_date_method_interval_format, 0)
00469        PHP_ME_MAPPING(createFromDateString, date_interval_create_from_date_string,  arginfo_date_interval_create_from_date_string, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
00470        PHP_FE_END
00471 };
00472 
00473 const zend_function_entry date_funcs_period[] = {
00474        PHP_ME(DatePeriod,                __construct,                 arginfo_date_period_construct, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
00475        PHP_FE_END
00476 };
00477 
00478 static char* guess_timezone(const timelib_tzdb *tzdb TSRMLS_DC);
00479 static void date_register_classes(TSRMLS_D);
00480 /* }}} */
00481 
00482 ZEND_DECLARE_MODULE_GLOBALS(date)
00483 static PHP_GINIT_FUNCTION(date);
00484 
00485 /* True global */
00486 timelib_tzdb *php_date_global_timezone_db;
00487 int php_date_global_timezone_db_enabled;
00488 
00489 #define DATE_DEFAULT_LATITUDE "31.7667"
00490 #define DATE_DEFAULT_LONGITUDE "35.2333"
00491 
00492 /* on 90'35; common sunset declaration (start of sun body appear) */
00493 #define DATE_SUNSET_ZENITH "90.583333"
00494 
00495 /* on 90'35; common sunrise declaration (sun body disappeared) */
00496 #define DATE_SUNRISE_ZENITH "90.583333"
00497 
00498 /* {{{ INI Settings */
00499 PHP_INI_BEGIN()
00500        STD_PHP_INI_ENTRY("date.timezone", "", PHP_INI_ALL, OnUpdateString, default_timezone, zend_date_globals, date_globals)
00501        PHP_INI_ENTRY("date.default_latitude",           DATE_DEFAULT_LATITUDE,        PHP_INI_ALL, NULL)
00502        PHP_INI_ENTRY("date.default_longitude",          DATE_DEFAULT_LONGITUDE,       PHP_INI_ALL, NULL)
00503        PHP_INI_ENTRY("date.sunset_zenith",              DATE_SUNSET_ZENITH,           PHP_INI_ALL, NULL)
00504        PHP_INI_ENTRY("date.sunrise_zenith",             DATE_SUNRISE_ZENITH,          PHP_INI_ALL, NULL)
00505 PHP_INI_END()
00506 /* }}} */
00507 
00508 zend_class_entry *date_ce_date, *date_ce_timezone, *date_ce_interval, *date_ce_period;
00509 
00510 
00511 PHPAPI zend_class_entry *php_date_get_date_ce(void)
00512 {
00513        return date_ce_date;
00514 }
00515 
00516 PHPAPI zend_class_entry *php_date_get_timezone_ce(void)
00517 {
00518        return date_ce_timezone;
00519 }
00520 
00521 static zend_object_handlers date_object_handlers_date;
00522 static zend_object_handlers date_object_handlers_timezone;
00523 static zend_object_handlers date_object_handlers_interval;
00524 static zend_object_handlers date_object_handlers_period;
00525 
00526 #define DATE_SET_CONTEXT \
00527        zval *object; \
00528        object = getThis(); \
00529    
00530 #define DATE_FETCH_OBJECT   \
00531        php_date_obj *obj;   \
00532        DATE_SET_CONTEXT; \
00533        if (object) { \
00534               if (zend_parse_parameters_none() == FAILURE) {   \
00535                      return;       \
00536               }      \
00537        } else {      \
00538               if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, NULL, "O", &object, date_ce_date) == FAILURE) {     \
00539                      RETURN_FALSE; \
00540               }      \
00541        }      \
00542        obj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);       \
00543 
00544 #define DATE_CHECK_INITIALIZED(member, class_name) \
00545        if (!(member)) { \
00546               php_error_docref(NULL TSRMLS_CC, E_WARNING, "The " #class_name " object has not been correctly initialized by its constructor"); \
00547               RETURN_FALSE; \
00548        }
00549 
00550 static void date_object_free_storage_date(void *object TSRMLS_DC);
00551 static void date_object_free_storage_timezone(void *object TSRMLS_DC);
00552 static void date_object_free_storage_interval(void *object TSRMLS_DC);
00553 static void date_object_free_storage_period(void *object TSRMLS_DC);
00554 
00555 static zend_object_value date_object_new_date(zend_class_entry *class_type TSRMLS_DC);
00556 static zend_object_value date_object_new_timezone(zend_class_entry *class_type TSRMLS_DC);
00557 static zend_object_value date_object_new_interval(zend_class_entry *class_type TSRMLS_DC);
00558 static zend_object_value date_object_new_period(zend_class_entry *class_type TSRMLS_DC);
00559 
00560 static zend_object_value date_object_clone_date(zval *this_ptr TSRMLS_DC);
00561 static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC);
00562 static zend_object_value date_object_clone_interval(zval *this_ptr TSRMLS_DC);
00563 static zend_object_value date_object_clone_period(zval *this_ptr TSRMLS_DC);
00564 
00565 static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC);
00566 static HashTable *date_object_get_properties(zval *object TSRMLS_DC);
00567 static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC);
00568 
00569 zval *date_interval_read_property(zval *object, zval *member, int type TSRMLS_DC);
00570 void date_interval_write_property(zval *object, zval *member, zval *value TSRMLS_DC);
00571 
00572 /* {{{ Module struct */
00573 zend_module_entry date_module_entry = {
00574        STANDARD_MODULE_HEADER_EX,
00575        NULL,
00576        NULL,
00577        "date",                     /* extension name */
00578        date_functions,             /* function list */
00579        PHP_MINIT(date),            /* process startup */
00580        PHP_MSHUTDOWN(date),        /* process shutdown */
00581        PHP_RINIT(date),            /* request startup */
00582        PHP_RSHUTDOWN(date),        /* request shutdown */
00583        PHP_MINFO(date),            /* extension info */
00584        PHP_VERSION,                /* extension version */
00585        PHP_MODULE_GLOBALS(date),   /* globals descriptor */
00586        PHP_GINIT(date),            /* globals ctor */
00587        NULL,                       /* globals dtor */
00588        NULL,                       /* post deactivate */
00589        STANDARD_MODULE_PROPERTIES_EX
00590 };
00591 /* }}} */
00592 
00593 
00594 /* {{{ PHP_GINIT_FUNCTION */
00595 static PHP_GINIT_FUNCTION(date)
00596 {
00597        date_globals->default_timezone = NULL;
00598        date_globals->timezone = NULL;
00599        date_globals->tzcache = NULL;
00600 }
00601 /* }}} */
00602 
00603 
00604 static void _php_date_tzinfo_dtor(void *tzinfo)
00605 {
00606        timelib_tzinfo **tzi = (timelib_tzinfo **)tzinfo;
00607 
00608        timelib_tzinfo_dtor(*tzi);
00609 }
00610 
00611 /* {{{ PHP_RINIT_FUNCTION */
00612 PHP_RINIT_FUNCTION(date)
00613 {
00614        if (DATEG(timezone)) {
00615               efree(DATEG(timezone));
00616        }
00617        DATEG(timezone) = NULL;
00618        DATEG(tzcache) = NULL;
00619        DATEG(last_errors) = NULL;
00620 
00621        return SUCCESS;
00622 }
00623 /* }}} */
00624 
00625 /* {{{ PHP_RSHUTDOWN_FUNCTION */
00626 PHP_RSHUTDOWN_FUNCTION(date)
00627 {
00628        if (DATEG(timezone)) {
00629               efree(DATEG(timezone));
00630        }
00631        DATEG(timezone) = NULL;
00632        if(DATEG(tzcache)) {
00633               zend_hash_destroy(DATEG(tzcache));
00634               FREE_HASHTABLE(DATEG(tzcache));
00635               DATEG(tzcache) = NULL;
00636        }
00637        if (DATEG(last_errors)) {
00638               timelib_error_container_dtor(DATEG(last_errors));
00639               DATEG(last_errors) = NULL;
00640        }
00641 
00642        return SUCCESS;
00643 }
00644 /* }}} */
00645 
00646 #define DATE_TIMEZONEDB      php_date_global_timezone_db ? php_date_global_timezone_db : timelib_builtin_db()
00647 
00648 /*
00649  * RFC822, Section 5.1: http://www.ietf.org/rfc/rfc822.txt
00650  *  date-time   =  [ day "," ] date time        ; dd mm yy hh:mm:ss zzz
00651  *  day         =  "Mon"  / "Tue" /  "Wed"  / "Thu"  /  "Fri"  / "Sat" /  "Sun"
00652  *  date        =  1*2DIGIT month 2DIGIT        ; day month year e.g. 20 Jun 82
00653  *  month       =  "Jan"  /  "Feb" /  "Mar"  /  "Apr"  /  "May"  /  "Jun" /  "Jul"  /  "Aug"  /  "Sep"  /  "Oct" /  "Nov"  /  "Dec"
00654  *  time        =  hour zone                    ; ANSI and Military
00655  *  hour        =  2DIGIT ":" 2DIGIT [":" 2DIGIT] ; 00:00:00 - 23:59:59
00656  *  zone        =  "UT"  / "GMT"  /  "EST" / "EDT"  /  "CST" / "CDT"  /  "MST" / "MDT"  /  "PST" / "PDT"  /  1ALPHA  / ( ("+" / "-") 4DIGIT )
00657  */
00658 #define DATE_FORMAT_RFC822   "D, d M y H:i:s O"
00659 
00660 /*
00661  * RFC850, Section 2.1.4: http://www.ietf.org/rfc/rfc850.txt
00662  *  Format must be acceptable both to the ARPANET and to the getdate routine.
00663  *  One format that is acceptable to both is Weekday, DD-Mon-YY HH:MM:SS TIMEZONE
00664  *  TIMEZONE can be any timezone name (3 or more letters)
00665  */
00666 #define DATE_FORMAT_RFC850   "l, d-M-y H:i:s T"
00667 
00668 /*
00669  * RFC1036, Section 2.1.2: http://www.ietf.org/rfc/rfc1036.txt
00670  *  Its format must be acceptable both in RFC-822 and to the getdate(3)
00671  *  Wdy, DD Mon YY HH:MM:SS TIMEZONE
00672  *  There is no hope of having a complete list of timezones.  Universal
00673  *  Time (GMT), the North American timezones (PST, PDT, MST, MDT, CST,
00674  *  CDT, EST, EDT) and the +/-hhmm offset specifed in RFC-822 should be supported.
00675  */
00676 #define DATE_FORMAT_RFC1036  "D, d M y H:i:s O"
00677 
00678 /*
00679  * RFC1123, Section 5.2.14: http://www.ietf.org/rfc/rfc1123.txt
00680  *  RFC-822 Date and Time Specification: RFC-822 Section 5
00681  *  The syntax for the date is hereby changed to: date = 1*2DIGIT month 2*4DIGIT
00682  */
00683 #define DATE_FORMAT_RFC1123  "D, d M Y H:i:s O"
00684 
00685 /*
00686  * RFC2822, Section 3.3: http://www.ietf.org/rfc/rfc2822.txt
00687  *  FWS             =       ([*WSP CRLF] 1*WSP) /   ; Folding white space
00688  *  CFWS            =       *([FWS] comment) (([FWS] comment) / FWS)
00689  *  
00690  *  date-time       =       [ day-of-week "," ] date FWS time [CFWS]
00691  *  day-of-week     =       ([FWS] day-name)
00692  *  day-name        =       "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"
00693  *  date            =       day month year
00694  *  year            =       4*DIGIT
00695  *  month           =       (FWS month-name FWS)
00696  *  month-name      =       "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
00697  *  day             =       ([FWS] 1*2DIGIT)
00698  *  time            =       time-of-day FWS zone
00699  *  time-of-day     =       hour ":" minute [ ":" second ]
00700  *  hour            =       2DIGIT
00701  *  minute          =       2DIGIT
00702  *  second          =       2DIGIT
00703  *  zone            =       (( "+" / "-" ) 4DIGIT)
00704  */
00705 #define DATE_FORMAT_RFC2822  "D, d M Y H:i:s O"
00706 /*
00707  * RFC3339, Section 5.6: http://www.ietf.org/rfc/rfc3339.txt
00708  *  date-fullyear   = 4DIGIT
00709  *  date-month      = 2DIGIT  ; 01-12
00710  *  date-mday       = 2DIGIT  ; 01-28, 01-29, 01-30, 01-31 based on month/year
00711  *  
00712  *  time-hour       = 2DIGIT  ; 00-23
00713  *  time-minute     = 2DIGIT  ; 00-59
00714  *  time-second     = 2DIGIT  ; 00-58, 00-59, 00-60 based on leap second rules
00715  *  
00716  *  time-secfrac    = "." 1*DIGIT
00717  *  time-numoffset  = ("+" / "-") time-hour ":" time-minute
00718  *  time-offset     = "Z" / time-numoffset
00719  *  
00720  *  partial-time    = time-hour ":" time-minute ":" time-second [time-secfrac]
00721  *  full-date       = date-fullyear "-" date-month "-" date-mday
00722  *  full-time       = partial-time time-offset
00723  *  
00724  *  date-time       = full-date "T" full-time
00725  */
00726 #define DATE_FORMAT_RFC3339  "Y-m-d\\TH:i:sP"
00727 
00728 #define DATE_FORMAT_ISO8601  "Y-m-d\\TH:i:sO"
00729 
00730 #define DATE_TZ_ERRMSG \
00731        "It is not safe to rely on the system's timezone settings. You are " \
00732        "*required* to use the date.timezone setting or the " \
00733        "date_default_timezone_set() function. In case you used any of those " \
00734        "methods and you are still getting this warning, you most likely " \
00735        "misspelled the timezone identifier. "
00736 
00737 #define SUNFUNCS_RET_TIMESTAMP 0
00738 #define SUNFUNCS_RET_STRING    1
00739 #define SUNFUNCS_RET_DOUBLE    2
00740 
00741 
00742 /* {{{ PHP_MINIT_FUNCTION */
00743 PHP_MINIT_FUNCTION(date)
00744 {
00745        REGISTER_INI_ENTRIES();
00746        date_register_classes(TSRMLS_C);
00747 /*
00748  * RFC4287, Section 3.3: http://www.ietf.org/rfc/rfc4287.txt
00749  *   A Date construct is an element whose content MUST conform to the
00750  *   "date-time" production in [RFC3339].  In addition, an uppercase "T"
00751  *   character MUST be used to separate date and time, and an uppercase
00752  *   "Z" character MUST be present in the absence of a numeric time zone offset.
00753  */
00754        REGISTER_STRING_CONSTANT("DATE_ATOM",    DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
00755 /*
00756  * Preliminary specification: http://wp.netscape.com/newsref/std/cookie_spec.html
00757  *   "This is based on RFC 822, RFC 850,  RFC 1036, and  RFC 1123,
00758  *   with the variations that the only legal time zone is GMT
00759  *   and the separators between the elements of the date must be dashes."
00760  */
00761        REGISTER_STRING_CONSTANT("DATE_COOKIE",  DATE_FORMAT_RFC850,  CONST_CS | CONST_PERSISTENT);
00762        REGISTER_STRING_CONSTANT("DATE_ISO8601", DATE_FORMAT_ISO8601, CONST_CS | CONST_PERSISTENT);
00763        REGISTER_STRING_CONSTANT("DATE_RFC822",  DATE_FORMAT_RFC822,  CONST_CS | CONST_PERSISTENT);
00764        REGISTER_STRING_CONSTANT("DATE_RFC850",  DATE_FORMAT_RFC850,  CONST_CS | CONST_PERSISTENT);
00765        REGISTER_STRING_CONSTANT("DATE_RFC1036", DATE_FORMAT_RFC1036, CONST_CS | CONST_PERSISTENT);
00766        REGISTER_STRING_CONSTANT("DATE_RFC1123", DATE_FORMAT_RFC1123, CONST_CS | CONST_PERSISTENT);
00767        REGISTER_STRING_CONSTANT("DATE_RFC2822", DATE_FORMAT_RFC2822, CONST_CS | CONST_PERSISTENT);
00768        REGISTER_STRING_CONSTANT("DATE_RFC3339", DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
00769 /*
00770  * RSS 2.0 Specification: http://blogs.law.harvard.edu/tech/rss
00771  *   "All date-times in RSS conform to the Date and Time Specification of RFC 822,
00772  *   with the exception that the year may be expressed with two characters or four characters (four preferred)"
00773  */
00774        REGISTER_STRING_CONSTANT("DATE_RSS",     DATE_FORMAT_RFC1123, CONST_CS | CONST_PERSISTENT);
00775        REGISTER_STRING_CONSTANT("DATE_W3C",     DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
00776 
00777        REGISTER_LONG_CONSTANT("SUNFUNCS_RET_TIMESTAMP", SUNFUNCS_RET_TIMESTAMP, CONST_CS | CONST_PERSISTENT);
00778        REGISTER_LONG_CONSTANT("SUNFUNCS_RET_STRING", SUNFUNCS_RET_STRING, CONST_CS | CONST_PERSISTENT);
00779        REGISTER_LONG_CONSTANT("SUNFUNCS_RET_DOUBLE", SUNFUNCS_RET_DOUBLE, CONST_CS | CONST_PERSISTENT);
00780 
00781        php_date_global_timezone_db = NULL;
00782        php_date_global_timezone_db_enabled = 0;
00783        DATEG(last_errors) = NULL;
00784        return SUCCESS;
00785 }
00786 /* }}} */
00787 
00788 /* {{{ PHP_MSHUTDOWN_FUNCTION */
00789 PHP_MSHUTDOWN_FUNCTION(date)
00790 {
00791        UNREGISTER_INI_ENTRIES();
00792 
00793        if (DATEG(last_errors)) {
00794               timelib_error_container_dtor(DATEG(last_errors));
00795        }
00796 
00797        return SUCCESS;
00798 }
00799 /* }}} */
00800 
00801 /* {{{ PHP_MINFO_FUNCTION */
00802 PHP_MINFO_FUNCTION(date)
00803 {
00804        const timelib_tzdb *tzdb = DATE_TIMEZONEDB;
00805        
00806        php_info_print_table_start();
00807        php_info_print_table_row(2, "date/time support", "enabled");
00808        php_info_print_table_row(2, "\"Olson\" Timezone Database Version", tzdb->version);
00809        php_info_print_table_row(2, "Timezone Database", php_date_global_timezone_db_enabled ? "external" : "internal");
00810        php_info_print_table_row(2, "Default timezone", guess_timezone(tzdb TSRMLS_CC));
00811        php_info_print_table_end();
00812 
00813        DISPLAY_INI_ENTRIES();
00814 }
00815 /* }}} */
00816 
00817 /* {{{ Timezone Cache functions */
00818 static timelib_tzinfo *php_date_parse_tzfile(char *formal_tzname, const timelib_tzdb *tzdb TSRMLS_DC)
00819 {
00820        timelib_tzinfo *tzi, **ptzi;
00821 
00822        if(!DATEG(tzcache)) {
00823               ALLOC_HASHTABLE(DATEG(tzcache));
00824               zend_hash_init(DATEG(tzcache), 4, NULL, _php_date_tzinfo_dtor, 0);
00825        }
00826 
00827        if (zend_hash_find(DATEG(tzcache), formal_tzname, strlen(formal_tzname) + 1, (void **) &ptzi) == SUCCESS) {
00828               return *ptzi;
00829        }
00830 
00831        tzi = timelib_parse_tzfile(formal_tzname, tzdb);
00832        if (tzi) {
00833               zend_hash_add(DATEG(tzcache), formal_tzname, strlen(formal_tzname) + 1, (void *) &tzi, sizeof(timelib_tzinfo*), NULL);
00834        }
00835        return tzi;
00836 }
00837 
00838 timelib_tzinfo *php_date_parse_tzfile_wrapper(char *formal_tzname, const timelib_tzdb *tzdb)
00839 {
00840        TSRMLS_FETCH();
00841        return php_date_parse_tzfile(formal_tzname, tzdb TSRMLS_CC);
00842 }
00843 /* }}} */
00844 
00845 /* {{{ Helper functions */
00846 static char* guess_timezone(const timelib_tzdb *tzdb TSRMLS_DC)
00847 {
00848        char *env;
00849 
00850        /* Checking configure timezone */
00851        if (DATEG(timezone) && (strlen(DATEG(timezone)) > 0)) {
00852               return DATEG(timezone);
00853        }
00854        /* Check environment variable */
00855        env = getenv("TZ");
00856        if (env && *env && timelib_timezone_id_is_valid(env, tzdb)) {
00857               return env;
00858        }
00859        /* Check config setting for default timezone */
00860        if (!DATEG(default_timezone)) {
00861               /* Special case: ext/date wasn't initialized yet */
00862               zval ztz;
00863               
00864               if (SUCCESS == zend_get_configuration_directive("date.timezone", sizeof("date.timezone"), &ztz) &&
00865                   Z_TYPE(ztz) == IS_STRING &&
00866                   Z_STRLEN(ztz) > 0 &&
00867                   timelib_timezone_id_is_valid(Z_STRVAL(ztz), tzdb)) {
00868                      return Z_STRVAL(ztz);
00869               }
00870        } else if (*DATEG(default_timezone) && timelib_timezone_id_is_valid(DATEG(default_timezone), tzdb)) {
00871               return DATEG(default_timezone);
00872        }
00873 #if HAVE_TM_ZONE
00874        /* Try to guess timezone from system information */
00875        {
00876               struct tm *ta, tmbuf;
00877               time_t     the_time;
00878               char      *tzid = NULL;
00879               
00880               the_time = time(NULL);
00881               ta = php_localtime_r(&the_time, &tmbuf);
00882               if (ta) {
00883                      tzid = timelib_timezone_id_from_abbr(ta->tm_zone, ta->tm_gmtoff, ta->tm_isdst);
00884               }
00885               if (! tzid) {
00886                      tzid = "UTC";
00887               }
00888               
00889               php_error_docref(NULL TSRMLS_CC, E_WARNING, DATE_TZ_ERRMSG "We selected '%s' for '%s/%.1f/%s' instead", tzid, ta ? ta->tm_zone : "Unknown", ta ? (float) (ta->tm_gmtoff / 3600) : 0, ta ? (ta->tm_isdst ? "DST" : "no DST") : "Unknown");
00890               return tzid;
00891        }
00892 #endif
00893 #ifdef PHP_WIN32
00894        {
00895               char *tzid;
00896               TIME_ZONE_INFORMATION tzi;
00897 
00898               switch (GetTimeZoneInformation(&tzi))
00899               {
00900                      /* DST in effect */
00901                      case TIME_ZONE_ID_DAYLIGHT:
00902                             /* If user has disabled DST in the control panel, Windows returns 0 here */
00903                             if (tzi.DaylightBias == 0) {
00904                                    goto php_win_std_time;
00905                             }
00906                             
00907                             tzid = timelib_timezone_id_from_abbr("", (tzi.Bias + tzi.DaylightBias) * -60, 1);
00908                             if (! tzid) {
00909                                    tzid = "UTC";
00910                             }
00911                             php_error_docref(NULL TSRMLS_CC, E_WARNING, DATE_TZ_ERRMSG "We selected '%s' for '%.1f/DST' instead", tzid, ((tzi.Bias + tzi.DaylightBias) / -60.0));
00912                             break;
00913 
00914                      /* no DST or not in effect */
00915                      case TIME_ZONE_ID_UNKNOWN:
00916                      case TIME_ZONE_ID_STANDARD:
00917                      default:
00918 php_win_std_time:
00919                             tzid = timelib_timezone_id_from_abbr("", (tzi.Bias + tzi.StandardBias) * -60, 0);
00920                             if (! tzid) {
00921                                    tzid = "UTC";
00922                             }
00923                             php_error_docref(NULL TSRMLS_CC, E_WARNING, DATE_TZ_ERRMSG "We selected '%s' for '%.1f/no DST' instead", tzid, ((tzi.Bias + tzi.StandardBias) / -60.0));
00924                             break;
00925 
00926               }
00927               return tzid;
00928        }
00929 #elif defined(NETWARE)
00930        /* Try to guess timezone from system information */
00931        {
00932               char *tzid = timelib_timezone_id_from_abbr("", ((_timezone * -1) + (daylightOffset * daylightOnOff)), daylightOnOff);
00933               if (tzid) {
00934                      return tzid;
00935               }
00936        }
00937 #endif
00938        /* Fallback to UTC */
00939        php_error_docref(NULL TSRMLS_CC, E_WARNING, DATE_TZ_ERRMSG "We had to select 'UTC' because your platform doesn't provide functionality for the guessing algorithm");
00940        return "UTC";
00941 }
00942 
00943 PHPAPI timelib_tzinfo *get_timezone_info(TSRMLS_D)
00944 {
00945        char *tz;
00946        timelib_tzinfo *tzi;
00947 
00948        tz = guess_timezone(DATE_TIMEZONEDB TSRMLS_CC);
00949        tzi = php_date_parse_tzfile(tz, DATE_TIMEZONEDB TSRMLS_CC);
00950        if (! tzi) {
00951               php_error_docref(NULL TSRMLS_CC, E_ERROR, "Timezone database is corrupt - this should *never* happen!");
00952        }
00953        return tzi;
00954 }
00955 /* }}} */
00956 
00957 
00958 /* {{{ date() and gmdate() data */
00959 #include "ext/standard/php_smart_str.h"
00960 
00961 static char *mon_full_names[] = {
00962        "January", "February", "March", "April",
00963        "May", "June", "July", "August",
00964        "September", "October", "November", "December"
00965 };
00966 
00967 static char *mon_short_names[] = {
00968        "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
00969 };
00970 
00971 static char *day_full_names[] = {
00972        "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
00973 };
00974 
00975 static char *day_short_names[] = {
00976        "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
00977 };
00978 
00979 static char *english_suffix(timelib_sll number)
00980 {
00981        if (number >= 10 && number <= 19) {
00982               return "th";
00983        } else {
00984               switch (number % 10) {
00985                      case 1: return "st";
00986                      case 2: return "nd";
00987                      case 3: return "rd";
00988               }
00989        }
00990        return "th";
00991 }
00992 /* }}} */
00993 
00994 /* {{{ day of week helpers */
00995 char *php_date_full_day_name(timelib_sll y, timelib_sll m, timelib_sll d)
00996 {
00997        timelib_sll day_of_week = timelib_day_of_week(y, m, d);
00998        if (day_of_week < 0) {
00999               return "Unknown";
01000        } 
01001        return day_full_names[day_of_week];       
01002 }
01003 
01004 char *php_date_short_day_name(timelib_sll y, timelib_sll m, timelib_sll d)
01005 {
01006        timelib_sll day_of_week = timelib_day_of_week(y, m, d);
01007        if (day_of_week < 0) {
01008               return "Unknown";
01009        } 
01010        return day_short_names[day_of_week];      
01011 }
01012 /* }}} */
01013 
01014 /* {{{ date_format - (gm)date helper */
01015 static char *date_format(char *format, int format_len, timelib_time *t, int localtime)
01016 {
01017        smart_str            string = {0};
01018        int                  i, length;
01019        char                 buffer[97];
01020        timelib_time_offset *offset = NULL;
01021        timelib_sll          isoweek, isoyear;
01022        int                  rfc_colon;
01023 
01024        if (!format_len) {
01025               return estrdup("");
01026        }
01027 
01028        if (localtime) {
01029               if (t->zone_type == TIMELIB_ZONETYPE_ABBR) {
01030                      offset = timelib_time_offset_ctor();
01031                      offset->offset = (t->z - (t->dst * 60)) * -60;
01032                      offset->leap_secs = 0;
01033                      offset->is_dst = t->dst;
01034                      offset->abbr = strdup(t->tz_abbr);
01035               } else if (t->zone_type == TIMELIB_ZONETYPE_OFFSET) {
01036                      offset = timelib_time_offset_ctor();
01037                      offset->offset = (t->z) * -60;
01038                      offset->leap_secs = 0;
01039                      offset->is_dst = 0;
01040                      offset->abbr = malloc(9); /* GMT�xxxx\0 */
01041                      snprintf(offset->abbr, 9, "GMT%c%02d%02d", 
01042                                                localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
01043                                                localtime ? abs(offset->offset / 3600) : 0,
01044                                                localtime ? abs((offset->offset % 3600) / 60) : 0 );
01045               } else {
01046                      offset = timelib_get_time_zone_info(t->sse, t->tz_info);
01047               }
01048        }
01049        timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear);
01050 
01051        for (i = 0; i < format_len; i++) {
01052               rfc_colon = 0;
01053               switch (format[i]) {
01054                      /* day */
01055                      case 'd': length = slprintf(buffer, 32, "%02d", (int) t->d); break;
01056                      case 'D': length = slprintf(buffer, 32, "%s", php_date_short_day_name(t->y, t->m, t->d)); break;
01057                      case 'j': length = slprintf(buffer, 32, "%d", (int) t->d); break;
01058                      case 'l': length = slprintf(buffer, 32, "%s", php_date_full_day_name(t->y, t->m, t->d)); break;
01059                      case 'S': length = slprintf(buffer, 32, "%s", english_suffix(t->d)); break;
01060                      case 'w': length = slprintf(buffer, 32, "%d", (int) timelib_day_of_week(t->y, t->m, t->d)); break;
01061                      case 'N': length = slprintf(buffer, 32, "%d", (int) timelib_iso_day_of_week(t->y, t->m, t->d)); break;
01062                      case 'z': length = slprintf(buffer, 32, "%d", (int) timelib_day_of_year(t->y, t->m, t->d)); break;
01063 
01064                      /* week */
01065                      case 'W': length = slprintf(buffer, 32, "%02d", (int) isoweek); break; /* iso weeknr */
01066                      case 'o': length = slprintf(buffer, 32, "%d", (int) isoyear); break; /* iso year */
01067 
01068                      /* month */
01069                      case 'F': length = slprintf(buffer, 32, "%s", mon_full_names[t->m - 1]); break;
01070                      case 'm': length = slprintf(buffer, 32, "%02d", (int) t->m); break;
01071                      case 'M': length = slprintf(buffer, 32, "%s", mon_short_names[t->m - 1]); break;
01072                      case 'n': length = slprintf(buffer, 32, "%d", (int) t->m); break;
01073                      case 't': length = slprintf(buffer, 32, "%d", (int) timelib_days_in_month(t->y, t->m)); break;
01074 
01075                      /* year */
01076                      case 'L': length = slprintf(buffer, 32, "%d", timelib_is_leap((int) t->y)); break;
01077                      case 'y': length = slprintf(buffer, 32, "%02d", (int) t->y % 100); break;
01078                      case 'Y': length = slprintf(buffer, 32, "%s%04lld", t->y < 0 ? "-" : "", php_date_llabs((timelib_sll) t->y)); break;
01079 
01080                      /* time */
01081                      case 'a': length = slprintf(buffer, 32, "%s", t->h >= 12 ? "pm" : "am"); break;
01082                      case 'A': length = slprintf(buffer, 32, "%s", t->h >= 12 ? "PM" : "AM"); break;
01083                      case 'B': {
01084                             int retval = (((((long)t->sse)-(((long)t->sse) - ((((long)t->sse) % 86400) + 3600))) * 10) / 864);                     
01085                             while (retval < 0) {
01086                                    retval += 1000;
01087                             }
01088                             retval = retval % 1000;
01089                             length = slprintf(buffer, 32, "%03d", retval);
01090                             break;
01091                      }
01092                      case 'g': length = slprintf(buffer, 32, "%d", (t->h % 12) ? (int) t->h % 12 : 12); break;
01093                      case 'G': length = slprintf(buffer, 32, "%d", (int) t->h); break;
01094                      case 'h': length = slprintf(buffer, 32, "%02d", (t->h % 12) ? (int) t->h % 12 : 12); break;
01095                      case 'H': length = slprintf(buffer, 32, "%02d", (int) t->h); break;
01096                      case 'i': length = slprintf(buffer, 32, "%02d", (int) t->i); break;
01097                      case 's': length = slprintf(buffer, 32, "%02d", (int) t->s); break;
01098                      case 'u': length = slprintf(buffer, 32, "%06d", (int) floor(t->f * 1000000)); break;
01099 
01100                      /* timezone */
01101                      case 'I': length = slprintf(buffer, 32, "%d", localtime ? offset->is_dst : 0); break;
01102                      case 'P': rfc_colon = 1; /* break intentionally missing */
01103                      case 'O': length = slprintf(buffer, 32, "%c%02d%s%02d",
01104                                                                              localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
01105                                                                              localtime ? abs(offset->offset / 3600) : 0,
01106                                                                              rfc_colon ? ":" : "",
01107                                                                              localtime ? abs((offset->offset % 3600) / 60) : 0
01108                                                    );
01109                                      break;
01110                      case 'T': length = slprintf(buffer, 32, "%s", localtime ? offset->abbr : "GMT"); break;
01111                      case 'e': if (!localtime) {
01112                                          length = slprintf(buffer, 32, "%s", "UTC");
01113                                      } else {
01114                                             switch (t->zone_type) {
01115                                                    case TIMELIB_ZONETYPE_ID:
01116                                                           length = slprintf(buffer, 32, "%s", t->tz_info->name);
01117                                                           break;
01118                                                    case TIMELIB_ZONETYPE_ABBR:
01119                                                           length = slprintf(buffer, 32, "%s", offset->abbr);
01120                                                           break;
01121                                                    case TIMELIB_ZONETYPE_OFFSET:
01122                                                           length = slprintf(buffer, 32, "%c%02d:%02d",
01123                                                                                     ((offset->offset < 0) ? '-' : '+'),
01124                                                                                     abs(offset->offset / 3600),
01125                                                                                     abs((offset->offset % 3600) / 60)
01126                                                                          );
01127                                                           break;
01128                                             }
01129                                      }
01130                                      break;
01131                      case 'Z': length = slprintf(buffer, 32, "%d", localtime ? offset->offset : 0); break;
01132 
01133                      /* full date/time */
01134                      case 'c': length = slprintf(buffer, 96, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
01135                                                                  (int) t->y, (int) t->m, (int) t->d,
01136                                                                              (int) t->h, (int) t->i, (int) t->s,
01137                                                                              localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
01138                                                                              localtime ? abs(offset->offset / 3600) : 0,
01139                                                                              localtime ? abs((offset->offset % 3600) / 60) : 0
01140                                                    );
01141                                      break;
01142                      case 'r': length = slprintf(buffer, 96, "%3s, %02d %3s %04d %02d:%02d:%02d %c%02d%02d",
01143                                                                  php_date_short_day_name(t->y, t->m, t->d),
01144                                                                              (int) t->d, mon_short_names[t->m - 1],
01145                                                                              (int) t->y, (int) t->h, (int) t->i, (int) t->s,
01146                                                                              localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
01147                                                                              localtime ? abs(offset->offset / 3600) : 0,
01148                                                                              localtime ? abs((offset->offset % 3600) / 60) : 0
01149                                                    );
01150                                      break;
01151                      case 'U': length = slprintf(buffer, 32, "%lld", (timelib_sll) t->sse); break;
01152 
01153                      case '\\': if (i < format_len) i++; /* break intentionally missing */
01154 
01155                      default: buffer[0] = format[i]; buffer[1] = '\0'; length = 1; break;
01156               }
01157               smart_str_appendl(&string, buffer, length);
01158        }
01159 
01160        smart_str_0(&string);
01161 
01162        if (localtime) {
01163               timelib_time_offset_dtor(offset);
01164        }
01165 
01166        return string.c;
01167 }
01168 
01169 static void php_date(INTERNAL_FUNCTION_PARAMETERS, int localtime)
01170 {
01171        char   *format;
01172        int     format_len;
01173        long    ts;
01174        char   *string;
01175 
01176        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &format, &format_len, &ts) == FAILURE) {
01177               RETURN_FALSE;
01178        }
01179        if (ZEND_NUM_ARGS() == 1) {
01180               ts = time(NULL);
01181        }
01182 
01183        string = php_format_date(format, format_len, ts, localtime TSRMLS_CC);
01184        
01185        RETVAL_STRING(string, 0);
01186 }
01187 /* }}} */
01188 
01189 PHPAPI char *php_format_date(char *format, int format_len, time_t ts, int localtime TSRMLS_DC) /* {{{ */
01190 {
01191        timelib_time   *t;
01192        timelib_tzinfo *tzi;
01193        char *string;
01194 
01195        t = timelib_time_ctor();
01196 
01197        if (localtime) {
01198               tzi = get_timezone_info(TSRMLS_C);
01199               t->tz_info = tzi;
01200               t->zone_type = TIMELIB_ZONETYPE_ID;
01201               timelib_unixtime2local(t, ts);
01202        } else {
01203               tzi = NULL;
01204               timelib_unixtime2gmt(t, ts);
01205        }
01206 
01207        string = date_format(format, format_len, t, localtime);
01208        
01209        timelib_time_dtor(t);
01210        return string;
01211 }
01212 /* }}} */
01213 
01214 /* {{{ php_idate
01215  */
01216 PHPAPI int php_idate(char format, time_t ts, int localtime)
01217 {
01218        timelib_time   *t;
01219        timelib_tzinfo *tzi;
01220        int retval = -1;
01221        timelib_time_offset *offset = NULL;
01222        timelib_sll isoweek, isoyear;
01223        TSRMLS_FETCH();
01224 
01225        t = timelib_time_ctor();
01226 
01227        if (!localtime) {
01228               tzi = get_timezone_info(TSRMLS_C);
01229               t->tz_info = tzi;
01230               t->zone_type = TIMELIB_ZONETYPE_ID;
01231               timelib_unixtime2local(t, ts);
01232        } else {
01233               tzi = NULL;
01234               timelib_unixtime2gmt(t, ts);
01235        }
01236 
01237        if (!localtime) {
01238               if (t->zone_type == TIMELIB_ZONETYPE_ABBR) {
01239                      offset = timelib_time_offset_ctor();
01240                      offset->offset = (t->z - (t->dst * 60)) * -60;
01241                      offset->leap_secs = 0;
01242                      offset->is_dst = t->dst;
01243                      offset->abbr = strdup(t->tz_abbr);
01244               } else if (t->zone_type == TIMELIB_ZONETYPE_OFFSET) {
01245                      offset = timelib_time_offset_ctor();
01246                      offset->offset = (t->z - (t->dst * 60)) * -60;
01247                      offset->leap_secs = 0;
01248                      offset->is_dst = t->dst;
01249                      offset->abbr = malloc(9); /* GMT�xxxx\0 */
01250                      snprintf(offset->abbr, 9, "GMT%c%02d%02d", 
01251                                                !localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
01252                                                !localtime ? abs(offset->offset / 3600) : 0,
01253                                                !localtime ? abs((offset->offset % 3600) / 60) : 0 );
01254               } else {
01255                      offset = timelib_get_time_zone_info(t->sse, t->tz_info);
01256               }
01257        }
01258 
01259        timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear);
01260 
01261        switch (format) {
01262               /* day */
01263               case 'd': case 'j': retval = (int) t->d; break;
01264 
01265               case 'w': retval = (int) timelib_day_of_week(t->y, t->m, t->d); break;
01266               case 'z': retval = (int) timelib_day_of_year(t->y, t->m, t->d); break;
01267 
01268               /* week */
01269               case 'W': retval = (int) isoweek; break; /* iso weeknr */
01270 
01271               /* month */
01272               case 'm': case 'n': retval = (int) t->m; break;
01273               case 't': retval = (int) timelib_days_in_month(t->y, t->m); break;
01274 
01275               /* year */
01276               case 'L': retval = (int) timelib_is_leap((int) t->y); break;
01277               case 'y': retval = (int) (t->y % 100); break;
01278               case 'Y': retval = (int) t->y; break;
01279 
01280               /* Swatch Beat a.k.a. Internet Time */
01281               case 'B':
01282                      retval = (((((long)t->sse)-(((long)t->sse) - ((((long)t->sse) % 86400) + 3600))) * 10) / 864);                  
01283                      while (retval < 0) {
01284                             retval += 1000;
01285                      }
01286                      retval = retval % 1000;
01287                      break;
01288 
01289               /* time */
01290               case 'g': case 'h': retval = (int) ((t->h % 12) ? (int) t->h % 12 : 12); break;
01291               case 'H': case 'G': retval = (int) t->h; break;
01292               case 'i': retval = (int) t->i; break;
01293               case 's': retval = (int) t->s; break;
01294 
01295               /* timezone */
01296               case 'I': retval = (int) (!localtime ? offset->is_dst : 0); break;
01297               case 'Z': retval = (int) (!localtime ? offset->offset : 0); break;
01298 
01299               case 'U': retval = (int) t->sse; break;
01300        }
01301 
01302        if (!localtime) {
01303               timelib_time_offset_dtor(offset);
01304        }
01305        timelib_time_dtor(t);
01306 
01307        return retval;
01308 }
01309 /* }}} */
01310 
01311 /* {{{ proto string date(string format [, long timestamp])
01312    Format a local date/time */
01313 PHP_FUNCTION(date)
01314 {
01315        php_date(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
01316 }
01317 /* }}} */
01318 
01319 /* {{{ proto string gmdate(string format [, long timestamp])
01320    Format a GMT date/time */
01321 PHP_FUNCTION(gmdate)
01322 {
01323        php_date(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
01324 }
01325 /* }}} */
01326 
01327 /* {{{ proto int idate(string format [, int timestamp])
01328    Format a local time/date as integer */
01329 PHP_FUNCTION(idate)
01330 {
01331        char   *format;
01332        int     format_len;
01333        long    ts = 0;
01334        int ret; 
01335 
01336        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &format, &format_len, &ts) == FAILURE) {
01337               RETURN_FALSE;
01338        }
01339 
01340        if (format_len != 1) {
01341               php_error_docref(NULL TSRMLS_CC, E_WARNING, "idate format is one char");
01342               RETURN_FALSE;
01343        }
01344 
01345        if (ZEND_NUM_ARGS() == 1) {
01346               ts = time(NULL);
01347        }
01348 
01349        ret = php_idate(format[0], ts, 0);
01350        if (ret == -1) {
01351               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unrecognized date format token.");
01352               RETURN_FALSE;
01353        }
01354        RETURN_LONG(ret);
01355 }
01356 /* }}} */
01357 
01358 /* {{{ php_date_set_tzdb - NOT THREADSAFE */
01359 PHPAPI void php_date_set_tzdb(timelib_tzdb *tzdb)
01360 {
01361        const timelib_tzdb *builtin = timelib_builtin_db();
01362        
01363        if (php_version_compare(tzdb->version, builtin->version) > 0) {
01364               php_date_global_timezone_db = tzdb;
01365               php_date_global_timezone_db_enabled = 1;
01366        }
01367 }
01368 /* }}} */
01369 
01370 /* {{{ php_parse_date: Backwards compability function */
01371 PHPAPI signed long php_parse_date(char *string, signed long *now)
01372 {
01373        timelib_time *parsed_time;
01374        timelib_error_container *error = NULL;
01375        int           error2;
01376        signed long   retval;
01377 
01378        parsed_time = timelib_strtotime(string, strlen(string), &error, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
01379        if (error->error_count) {
01380               timelib_error_container_dtor(error);
01381               return -1;
01382        }
01383        timelib_error_container_dtor(error);
01384        timelib_update_ts(parsed_time, NULL);
01385        retval = timelib_date_to_int(parsed_time, &error2);
01386        timelib_time_dtor(parsed_time);
01387        if (error2) {
01388               return -1;
01389        }
01390        return retval;
01391 }
01392 /* }}} */
01393 
01394 
01395 /* {{{ proto int strtotime(string time [, int now ])
01396    Convert string representation of date and time to a timestamp */
01397 PHP_FUNCTION(strtotime)
01398 {
01399        char *times, *initial_ts;
01400        int   time_len, error1, error2;
01401        struct timelib_error_container *error;
01402        long  preset_ts = 0, ts;
01403 
01404        timelib_time *t, *now;
01405        timelib_tzinfo *tzi;
01406 
01407        tzi = get_timezone_info(TSRMLS_C);
01408 
01409        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "sl", &times, &time_len, &preset_ts) != FAILURE) {
01410               /* We have an initial timestamp */
01411               now = timelib_time_ctor();
01412 
01413               initial_ts = emalloc(25);
01414               snprintf(initial_ts, 24, "@%ld UTC", preset_ts);
01415               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 */
01416               timelib_update_ts(t, tzi);
01417               now->tz_info = tzi;
01418               now->zone_type = TIMELIB_ZONETYPE_ID;
01419               timelib_unixtime2local(now, t->sse);
01420               timelib_time_dtor(t);
01421               efree(initial_ts);
01422        } else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &times, &time_len, &preset_ts) != FAILURE) {
01423               /* We have no initial timestamp */
01424               now = timelib_time_ctor();
01425               now->tz_info = tzi;
01426               now->zone_type = TIMELIB_ZONETYPE_ID;
01427               timelib_unixtime2local(now, (timelib_sll) time(NULL));
01428        } else {
01429               RETURN_FALSE;
01430        }
01431 
01432        if (!time_len) {
01433               timelib_time_dtor(now);     
01434               RETURN_FALSE;
01435        }
01436 
01437        t = timelib_strtotime(times, time_len, &error, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
01438        error1 = error->error_count;
01439        timelib_error_container_dtor(error);
01440        timelib_fill_holes(t, now, TIMELIB_NO_CLONE);
01441        timelib_update_ts(t, tzi);
01442        ts = timelib_date_to_int(t, &error2);
01443 
01444        timelib_time_dtor(now);
01445        timelib_time_dtor(t);
01446 
01447        if (error1 || error2) {
01448               RETURN_FALSE;
01449        } else {
01450               RETURN_LONG(ts);
01451        }
01452 }
01453 /* }}} */
01454 
01455 
01456 /* {{{ php_mktime - (gm)mktime helper */
01457 PHPAPI void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
01458 {
01459        long hou = 0, min = 0, sec = 0, mon = 0, day = 0, yea = 0, dst = -1;
01460        timelib_time *now;
01461        timelib_tzinfo *tzi = NULL;
01462        long ts, adjust_seconds = 0;
01463        int error;
01464 
01465        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lllllll", &hou, &min, &sec, &mon, &day, &yea, &dst) == FAILURE) {
01466               RETURN_FALSE;
01467        }
01468        /* Initialize structure with current time */
01469        now = timelib_time_ctor();
01470        if (gmt) {
01471               timelib_unixtime2gmt(now, (timelib_sll) time(NULL));
01472        } else {
01473               tzi = get_timezone_info(TSRMLS_C);
01474               now->tz_info = tzi;
01475               now->zone_type = TIMELIB_ZONETYPE_ID;
01476               timelib_unixtime2local(now, (timelib_sll) time(NULL));
01477        }
01478        /* Fill in the new data */
01479        switch (ZEND_NUM_ARGS()) {
01480               case 7:
01481                      /* break intentionally missing */
01482               case 6:
01483                      if (yea >= 0 && yea < 70) {
01484                             yea += 2000;
01485                      } else if (yea >= 70 && yea <= 100) {
01486                             yea += 1900;
01487                      }
01488                      now->y = yea;
01489                      /* break intentionally missing again */
01490               case 5:
01491                      now->d = day;
01492                      /* break missing intentionally here too */
01493               case 4:
01494                      now->m = mon;
01495                      /* and here */
01496               case 3:
01497                      now->s = sec;
01498                      /* yup, this break isn't here on purpose too */
01499               case 2:
01500                      now->i = min;
01501                      /* last intentionally missing break */
01502               case 1:
01503                      now->h = hou;
01504                      break;
01505               default:
01506                      php_error_docref(NULL TSRMLS_CC, E_STRICT, "You should be using the time() function instead");
01507        }
01508        /* Update the timestamp */
01509        if (gmt) {
01510               timelib_update_ts(now, NULL);
01511        } else {
01512               timelib_update_ts(now, tzi);
01513        }
01514        /* Support for the deprecated is_dst parameter */
01515        if (dst != -1) {
01516               php_error_docref(NULL TSRMLS_CC, E_DEPRECATED, "The is_dst parameter is deprecated");
01517               if (gmt) {
01518                      /* GMT never uses DST */
01519                      if (dst == 1) {
01520                             adjust_seconds = -3600;
01521                      }
01522               } else {
01523                      /* Figure out is_dst for current TS */
01524                      timelib_time_offset *tmp_offset;
01525                      tmp_offset = timelib_get_time_zone_info(now->sse, tzi);
01526                      if (dst == 1 && tmp_offset->is_dst == 0) {
01527                             adjust_seconds = -3600;
01528                      }
01529                      if (dst == 0 && tmp_offset->is_dst == 1) {
01530                             adjust_seconds = +3600;
01531                      }
01532                      timelib_time_offset_dtor(tmp_offset);
01533               }
01534        }
01535        /* Clean up and return */
01536        ts = timelib_date_to_int(now, &error);
01537        ts += adjust_seconds;
01538        timelib_time_dtor(now);
01539 
01540        if (error) {
01541               RETURN_FALSE;
01542        } else {
01543               RETURN_LONG(ts);
01544        }
01545 }
01546 /* }}} */
01547 
01548 /* {{{ proto int mktime([int hour [, int min [, int sec [, int mon [, int day [, int year]]]]]])
01549    Get UNIX timestamp for a date */
01550 PHP_FUNCTION(mktime)
01551 {
01552        php_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
01553 }
01554 /* }}} */
01555 
01556 /* {{{ proto int gmmktime([int hour [, int min [, int sec [, int mon [, int day [, int year]]]]]])
01557    Get UNIX timestamp for a GMT date */
01558 PHP_FUNCTION(gmmktime)
01559 {
01560        php_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
01561 }
01562 /* }}} */
01563 
01564 
01565 /* {{{ proto bool checkdate(int month, int day, int year)
01566    Returns true(1) if it is a valid date in gregorian calendar */
01567 PHP_FUNCTION(checkdate)
01568 {
01569        long m, d, y;
01570 
01571        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &m, &d, &y) == FAILURE) {
01572               RETURN_FALSE;
01573        }
01574 
01575        if (y < 1 || y > 32767 || !timelib_valid_date(y, m, d)) {
01576               RETURN_FALSE;
01577        }
01578        RETURN_TRUE;  /* True : This month, day, year arguments are valid */
01579 }
01580 /* }}} */
01581 
01582 #ifdef HAVE_STRFTIME
01583 /* {{{ php_strftime - (gm)strftime helper */
01584 PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
01585 {
01586        char                *format, *buf;
01587        int                  format_len;
01588        long                 timestamp = 0;
01589        struct tm            ta;
01590        int                  max_reallocs = 5;
01591        size_t               buf_len = 64, real_len;
01592        timelib_time        *ts;
01593        timelib_tzinfo      *tzi;
01594        timelib_time_offset *offset = NULL;
01595 
01596        timestamp = (long) time(NULL);
01597 
01598        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &format, &format_len, &timestamp) == FAILURE) {
01599               RETURN_FALSE;
01600        }
01601 
01602        if (format_len == 0) {
01603               RETURN_FALSE;
01604        }
01605 
01606        ts = timelib_time_ctor();
01607        if (gmt) {
01608               tzi = NULL;
01609               timelib_unixtime2gmt(ts, (timelib_sll) timestamp);
01610        } else {
01611               tzi = get_timezone_info(TSRMLS_C);
01612               ts->tz_info = tzi;
01613               ts->zone_type = TIMELIB_ZONETYPE_ID;
01614               timelib_unixtime2local(ts, (timelib_sll) timestamp);
01615        }
01616        ta.tm_sec   = ts->s;
01617        ta.tm_min   = ts->i;
01618        ta.tm_hour  = ts->h;
01619        ta.tm_mday  = ts->d;
01620        ta.tm_mon   = ts->m - 1;
01621        ta.tm_year  = ts->y - 1900;
01622        ta.tm_wday  = timelib_day_of_week(ts->y, ts->m, ts->d);
01623        ta.tm_yday  = timelib_day_of_year(ts->y, ts->m, ts->d);
01624        if (gmt) {
01625               ta.tm_isdst = 0;
01626 #if HAVE_TM_GMTOFF
01627               ta.tm_gmtoff = 0;
01628 #endif
01629 #if HAVE_TM_ZONE
01630               ta.tm_zone = "GMT";
01631 #endif
01632        } else {
01633               offset = timelib_get_time_zone_info(timestamp, tzi);
01634 
01635               ta.tm_isdst = offset->is_dst;
01636 #if HAVE_TM_GMTOFF
01637               ta.tm_gmtoff = offset->offset;
01638 #endif
01639 #if HAVE_TM_ZONE
01640               ta.tm_zone = offset->abbr;
01641 #endif
01642        }
01643 
01644        buf = (char *) emalloc(buf_len);
01645        while ((real_len=strftime(buf, buf_len, format, &ta))==buf_len || real_len==0) {
01646               buf_len *= 2;
01647               buf = (char *) erealloc(buf, buf_len);
01648               if (!--max_reallocs) {
01649                      break;
01650               }
01651        }
01652 
01653        timelib_time_dtor(ts);
01654        if (!gmt) {
01655               timelib_time_offset_dtor(offset);
01656        }
01657 
01658        if (real_len && real_len != buf_len) {
01659               buf = (char *) erealloc(buf, real_len + 1);
01660               RETURN_STRINGL(buf, real_len, 0);
01661        }
01662        efree(buf);
01663        RETURN_FALSE;
01664 }
01665 /* }}} */
01666 
01667 /* {{{ proto string strftime(string format [, int timestamp])
01668    Format a local time/date according to locale settings */
01669 PHP_FUNCTION(strftime)
01670 {
01671        php_strftime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
01672 }
01673 /* }}} */
01674 
01675 /* {{{ proto string gmstrftime(string format [, int timestamp])
01676    Format a GMT/UCT time/date according to locale settings */
01677 PHP_FUNCTION(gmstrftime)
01678 {
01679        php_strftime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
01680 }
01681 /* }}} */
01682 #endif
01683 
01684 /* {{{ proto int time(void)
01685    Return current UNIX timestamp */
01686 PHP_FUNCTION(time)
01687 {
01688        RETURN_LONG((long)time(NULL));
01689 }
01690 /* }}} */
01691 
01692 /* {{{ proto array localtime([int timestamp [, bool associative_array]])
01693    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 */
01694 PHP_FUNCTION(localtime)
01695 {
01696        long timestamp = (long)time(NULL);
01697        zend_bool associative = 0;
01698        timelib_tzinfo *tzi;
01699        timelib_time   *ts;
01700 
01701        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lb", &timestamp, &associative) == FAILURE) {
01702               RETURN_FALSE;
01703        }
01704 
01705        tzi = get_timezone_info(TSRMLS_C);
01706        ts = timelib_time_ctor();
01707        ts->tz_info = tzi;
01708        ts->zone_type = TIMELIB_ZONETYPE_ID;
01709        timelib_unixtime2local(ts, (timelib_sll) timestamp);
01710 
01711        array_init(return_value);
01712 
01713        if (associative) {
01714               add_assoc_long(return_value, "tm_sec",   ts->s);
01715               add_assoc_long(return_value, "tm_min",   ts->i);
01716               add_assoc_long(return_value, "tm_hour",  ts->h);
01717               add_assoc_long(return_value, "tm_mday",  ts->d);
01718               add_assoc_long(return_value, "tm_mon",   ts->m - 1);
01719               add_assoc_long(return_value, "tm_year",  ts->y - 1900);
01720               add_assoc_long(return_value, "tm_wday",  timelib_day_of_week(ts->y, ts->m, ts->d));
01721               add_assoc_long(return_value, "tm_yday",  timelib_day_of_year(ts->y, ts->m, ts->d));
01722               add_assoc_long(return_value, "tm_isdst", ts->dst);
01723        } else {
01724               add_next_index_long(return_value, ts->s);
01725               add_next_index_long(return_value, ts->i);
01726               add_next_index_long(return_value, ts->h);
01727               add_next_index_long(return_value, ts->d);
01728               add_next_index_long(return_value, ts->m - 1);
01729               add_next_index_long(return_value, ts->y- 1900);
01730               add_next_index_long(return_value, timelib_day_of_week(ts->y, ts->m, ts->d));
01731               add_next_index_long(return_value, timelib_day_of_year(ts->y, ts->m, ts->d));
01732               add_next_index_long(return_value, ts->dst);
01733        }
01734 
01735        timelib_time_dtor(ts);
01736 }
01737 /* }}} */
01738 
01739 /* {{{ proto array getdate([int timestamp])
01740    Get date/time information */
01741 PHP_FUNCTION(getdate)
01742 {
01743        long timestamp = (long)time(NULL);
01744        timelib_tzinfo *tzi;
01745        timelib_time   *ts;
01746 
01747        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &timestamp) == FAILURE) {
01748               RETURN_FALSE;
01749        }
01750 
01751        tzi = get_timezone_info(TSRMLS_C);
01752        ts = timelib_time_ctor();
01753        ts->tz_info = tzi;
01754        ts->zone_type = TIMELIB_ZONETYPE_ID;
01755        timelib_unixtime2local(ts, (timelib_sll) timestamp);
01756 
01757        array_init(return_value);
01758 
01759        add_assoc_long(return_value, "seconds", ts->s);
01760        add_assoc_long(return_value, "minutes", ts->i);
01761        add_assoc_long(return_value, "hours", ts->h);
01762        add_assoc_long(return_value, "mday", ts->d);
01763        add_assoc_long(return_value, "wday", timelib_day_of_week(ts->y, ts->m, ts->d));
01764        add_assoc_long(return_value, "mon", ts->m);
01765        add_assoc_long(return_value, "year", ts->y);
01766        add_assoc_long(return_value, "yday", timelib_day_of_year(ts->y, ts->m, ts->d));
01767        add_assoc_string(return_value, "weekday", php_date_full_day_name(ts->y, ts->m, ts->d), 1);
01768        add_assoc_string(return_value, "month", mon_full_names[ts->m - 1], 1);
01769        add_index_long(return_value, 0, timestamp);
01770 
01771        timelib_time_dtor(ts);
01772 }
01773 /* }}} */
01774 
01775 #define PHP_DATE_TIMEZONE_GROUP_AFRICA     0x0001
01776 #define PHP_DATE_TIMEZONE_GROUP_AMERICA    0x0002
01777 #define PHP_DATE_TIMEZONE_GROUP_ANTARCTICA 0x0004
01778 #define PHP_DATE_TIMEZONE_GROUP_ARCTIC     0x0008
01779 #define PHP_DATE_TIMEZONE_GROUP_ASIA       0x0010
01780 #define PHP_DATE_TIMEZONE_GROUP_ATLANTIC   0x0020
01781 #define PHP_DATE_TIMEZONE_GROUP_AUSTRALIA  0x0040
01782 #define PHP_DATE_TIMEZONE_GROUP_EUROPE     0x0080
01783 #define PHP_DATE_TIMEZONE_GROUP_INDIAN     0x0100
01784 #define PHP_DATE_TIMEZONE_GROUP_PACIFIC    0x0200
01785 #define PHP_DATE_TIMEZONE_GROUP_UTC        0x0400
01786 #define PHP_DATE_TIMEZONE_GROUP_ALL        0x07FF
01787 #define PHP_DATE_TIMEZONE_GROUP_ALL_W_BC   0x0FFF
01788 #define PHP_DATE_TIMEZONE_PER_COUNTRY      0x1000
01789 
01790 #define PHP_DATE_PERIOD_EXCLUDE_START_DATE 0x0001
01791 
01792 
01793 /* define an overloaded iterator structure */
01794 typedef struct {
01795        zend_object_iterator  intern;
01796        zval                 *date_period_zval;
01797        zval                 *current;
01798        php_period_obj       *object;
01799        int                   current_index;
01800 } date_period_it;
01801 
01802 /* {{{ date_period_it_invalidate_current */
01803 static void date_period_it_invalidate_current(zend_object_iterator *iter TSRMLS_DC)
01804 {
01805        date_period_it *iterator = (date_period_it *)iter;
01806 
01807        if (iterator->current) {
01808               zval_ptr_dtor(&iterator->current);
01809               iterator->current = NULL;
01810        }
01811 }
01812 /* }}} */
01813 
01814 
01815 /* {{{ date_period_it_dtor */
01816 static void date_period_it_dtor(zend_object_iterator *iter TSRMLS_DC)
01817 {
01818        date_period_it *iterator = (date_period_it *)iter;
01819 
01820        date_period_it_invalidate_current(iter TSRMLS_CC);
01821 
01822        zval_ptr_dtor(&iterator->date_period_zval);
01823 
01824        efree(iterator);
01825 }
01826 /* }}} */
01827 
01828 
01829 /* {{{ date_period_it_has_more */
01830 static int date_period_it_has_more(zend_object_iterator *iter TSRMLS_DC)
01831 {
01832        date_period_it *iterator = (date_period_it *)iter;
01833        php_period_obj *object   = iterator->object;
01834        timelib_time   *it_time = object->current;
01835 
01836        /* apply modification if it's not the first iteration */
01837        if (!object->include_start_date || iterator->current_index > 0) {
01838               it_time->have_relative = 1;
01839               it_time->relative = *object->interval;
01840               it_time->sse_uptodate = 0;
01841               timelib_update_ts(it_time, NULL);
01842               timelib_update_from_sse(it_time);
01843        }
01844 
01845        if (object->end) {
01846               return object->current->sse < object->end->sse ? SUCCESS : FAILURE;
01847        } else {
01848               return (iterator->current_index < object->recurrences) ? SUCCESS : FAILURE;
01849        }
01850 }
01851 /* }}} */
01852 
01853 
01854 /* {{{ date_period_it_current_data */
01855 static void date_period_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
01856 {
01857        date_period_it *iterator = (date_period_it *)iter;
01858        php_period_obj *object   = iterator->object;
01859        timelib_time   *it_time = object->current;
01860        php_date_obj   *newdateobj;
01861 
01862        /* Create new object */
01863        MAKE_STD_ZVAL(iterator->current);
01864        php_date_instantiate(date_ce_date, iterator->current TSRMLS_CC);
01865        newdateobj = (php_date_obj *) zend_object_store_get_object(iterator->current TSRMLS_CC);
01866        newdateobj->time = timelib_time_ctor();
01867        *newdateobj->time = *it_time;
01868        if (it_time->tz_abbr) {
01869               newdateobj->time->tz_abbr = strdup(it_time->tz_abbr);
01870        }
01871        if (it_time->tz_info) {
01872               newdateobj->time->tz_info = it_time->tz_info;
01873        }
01874        
01875        *data = &iterator->current;
01876 }
01877 /* }}} */
01878 
01879 
01880 /* {{{ date_period_it_current_key */
01881 static int date_period_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
01882 {
01883        date_period_it   *iterator = (date_period_it *)iter;
01884        *int_key = iterator->current_index;
01885        return HASH_KEY_IS_LONG;
01886 }
01887 /* }}} */
01888 
01889 
01890 /* {{{ date_period_it_move_forward */
01891 static void date_period_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
01892 {
01893        date_period_it   *iterator = (date_period_it *)iter;
01894 
01895        iterator->current_index++;
01896        date_period_it_invalidate_current(iter TSRMLS_CC);
01897 }
01898 /* }}} */
01899 
01900 
01901 /* {{{ date_period_it_rewind */
01902 static void date_period_it_rewind(zend_object_iterator *iter TSRMLS_DC)
01903 {
01904        date_period_it   *iterator = (date_period_it *)iter;
01905 
01906        iterator->current_index = 0;
01907        if (iterator->object->current) {
01908               timelib_time_dtor(iterator->object->current);
01909        }
01910        iterator->object->current = timelib_time_clone(iterator->object->start);
01911        date_period_it_invalidate_current(iter TSRMLS_CC);
01912 }
01913 /* }}} */
01914 
01915 
01916 /* iterator handler table */
01917 zend_object_iterator_funcs date_period_it_funcs = {
01918        date_period_it_dtor,
01919        date_period_it_has_more,
01920        date_period_it_current_data,
01921        date_period_it_current_key,
01922        date_period_it_move_forward,
01923        date_period_it_rewind,
01924        date_period_it_invalidate_current
01925 };
01926 
01927 
01928 
01929 zend_object_iterator *date_object_period_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
01930 {
01931        date_period_it  *iterator = emalloc(sizeof(date_period_it));
01932        php_period_obj  *dpobj    = (php_period_obj *)zend_object_store_get_object(object TSRMLS_CC);
01933 
01934        if (by_ref) {
01935               zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
01936        }
01937 
01938        Z_ADDREF_P(object);
01939        iterator->intern.data = (void*) dpobj;
01940        iterator->intern.funcs = &date_period_it_funcs;
01941        iterator->date_period_zval = object;
01942        iterator->object = dpobj;
01943        iterator->current = NULL;
01944 
01945        return (zend_object_iterator*)iterator;
01946 }
01947 
01948 static void date_register_classes(TSRMLS_D)
01949 {
01950        zend_class_entry ce_date, ce_timezone, ce_interval, ce_period;
01951 
01952        INIT_CLASS_ENTRY(ce_date, "DateTime", date_funcs_date);
01953        ce_date.create_object = date_object_new_date;
01954        date_ce_date = zend_register_internal_class_ex(&ce_date, NULL, NULL TSRMLS_CC);
01955        memcpy(&date_object_handlers_date, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
01956        date_object_handlers_date.clone_obj = date_object_clone_date;
01957        date_object_handlers_date.compare_objects = date_object_compare_date;
01958        date_object_handlers_date.get_properties = date_object_get_properties;
01959 
01960 #define REGISTER_DATE_CLASS_CONST_STRING(const_name, value) \
01961        zend_declare_class_constant_stringl(date_ce_date, const_name, sizeof(const_name)-1, value, sizeof(value)-1 TSRMLS_CC);
01962 
01963        REGISTER_DATE_CLASS_CONST_STRING("ATOM",    DATE_FORMAT_RFC3339);
01964        REGISTER_DATE_CLASS_CONST_STRING("COOKIE",  DATE_FORMAT_RFC850);
01965        REGISTER_DATE_CLASS_CONST_STRING("ISO8601", DATE_FORMAT_ISO8601);
01966        REGISTER_DATE_CLASS_CONST_STRING("RFC822",  DATE_FORMAT_RFC822);
01967        REGISTER_DATE_CLASS_CONST_STRING("RFC850",  DATE_FORMAT_RFC850);
01968        REGISTER_DATE_CLASS_CONST_STRING("RFC1036", DATE_FORMAT_RFC1036);
01969        REGISTER_DATE_CLASS_CONST_STRING("RFC1123", DATE_FORMAT_RFC1123);
01970        REGISTER_DATE_CLASS_CONST_STRING("RFC2822", DATE_FORMAT_RFC2822);
01971        REGISTER_DATE_CLASS_CONST_STRING("RFC3339", DATE_FORMAT_RFC3339);
01972        REGISTER_DATE_CLASS_CONST_STRING("RSS",     DATE_FORMAT_RFC1123);
01973        REGISTER_DATE_CLASS_CONST_STRING("W3C",     DATE_FORMAT_RFC3339);
01974 
01975 
01976        INIT_CLASS_ENTRY(ce_timezone, "DateTimeZone", date_funcs_timezone);
01977        ce_timezone.create_object = date_object_new_timezone;
01978        date_ce_timezone = zend_register_internal_class_ex(&ce_timezone, NULL, NULL TSRMLS_CC);
01979        memcpy(&date_object_handlers_timezone, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
01980        date_object_handlers_timezone.clone_obj = date_object_clone_timezone;
01981 
01982 #define REGISTER_TIMEZONE_CLASS_CONST_STRING(const_name, value) \
01983        zend_declare_class_constant_long(date_ce_timezone, const_name, sizeof(const_name)-1, value TSRMLS_CC);
01984 
01985        REGISTER_TIMEZONE_CLASS_CONST_STRING("AFRICA",      PHP_DATE_TIMEZONE_GROUP_AFRICA);
01986        REGISTER_TIMEZONE_CLASS_CONST_STRING("AMERICA",     PHP_DATE_TIMEZONE_GROUP_AMERICA);
01987        REGISTER_TIMEZONE_CLASS_CONST_STRING("ANTARCTICA",  PHP_DATE_TIMEZONE_GROUP_ANTARCTICA);
01988        REGISTER_TIMEZONE_CLASS_CONST_STRING("ARCTIC",      PHP_DATE_TIMEZONE_GROUP_ARCTIC);
01989        REGISTER_TIMEZONE_CLASS_CONST_STRING("ASIA",        PHP_DATE_TIMEZONE_GROUP_ASIA);
01990        REGISTER_TIMEZONE_CLASS_CONST_STRING("ATLANTIC",    PHP_DATE_TIMEZONE_GROUP_ATLANTIC);
01991        REGISTER_TIMEZONE_CLASS_CONST_STRING("AUSTRALIA",   PHP_DATE_TIMEZONE_GROUP_AUSTRALIA);
01992        REGISTER_TIMEZONE_CLASS_CONST_STRING("EUROPE",      PHP_DATE_TIMEZONE_GROUP_EUROPE);
01993        REGISTER_TIMEZONE_CLASS_CONST_STRING("INDIAN",      PHP_DATE_TIMEZONE_GROUP_INDIAN);
01994        REGISTER_TIMEZONE_CLASS_CONST_STRING("PACIFIC",     PHP_DATE_TIMEZONE_GROUP_PACIFIC);
01995        REGISTER_TIMEZONE_CLASS_CONST_STRING("UTC",         PHP_DATE_TIMEZONE_GROUP_UTC);
01996        REGISTER_TIMEZONE_CLASS_CONST_STRING("ALL",         PHP_DATE_TIMEZONE_GROUP_ALL);
01997        REGISTER_TIMEZONE_CLASS_CONST_STRING("ALL_WITH_BC", PHP_DATE_TIMEZONE_GROUP_ALL_W_BC);
01998        REGISTER_TIMEZONE_CLASS_CONST_STRING("PER_COUNTRY", PHP_DATE_TIMEZONE_PER_COUNTRY);
01999 
02000        INIT_CLASS_ENTRY(ce_interval, "DateInterval", date_funcs_interval);
02001        ce_interval.create_object = date_object_new_interval;
02002        date_ce_interval = zend_register_internal_class_ex(&ce_interval, NULL, NULL TSRMLS_CC);
02003        memcpy(&date_object_handlers_interval, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
02004        date_object_handlers_interval.clone_obj = date_object_clone_interval;
02005        date_object_handlers_interval.read_property = date_interval_read_property;
02006        date_object_handlers_interval.write_property = date_interval_write_property;
02007        date_object_handlers_interval.get_properties = date_object_get_properties_interval;
02008        date_object_handlers_interval.get_property_ptr_ptr = NULL;
02009 
02010        INIT_CLASS_ENTRY(ce_period, "DatePeriod", date_funcs_period);
02011        ce_period.create_object = date_object_new_period;
02012        date_ce_period = zend_register_internal_class_ex(&ce_period, NULL, NULL TSRMLS_CC);
02013        date_ce_period->get_iterator = date_object_period_get_iterator;
02014        date_ce_period->iterator_funcs.funcs = &date_period_it_funcs;
02015        zend_class_implements(date_ce_period TSRMLS_CC, 1, zend_ce_traversable);
02016        memcpy(&date_object_handlers_period, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
02017        date_object_handlers_period.clone_obj = date_object_clone_period;
02018 
02019 #define REGISTER_PERIOD_CLASS_CONST_STRING(const_name, value) \
02020        zend_declare_class_constant_long(date_ce_period, const_name, sizeof(const_name)-1, value TSRMLS_CC);
02021 
02022        REGISTER_PERIOD_CLASS_CONST_STRING("EXCLUDE_START_DATE", PHP_DATE_PERIOD_EXCLUDE_START_DATE);
02023 }
02024 
02025 static inline zend_object_value date_object_new_date_ex(zend_class_entry *class_type, php_date_obj **ptr TSRMLS_DC)
02026 {
02027        php_date_obj *intern;
02028        zend_object_value retval;
02029        zval *tmp;
02030 
02031        intern = emalloc(sizeof(php_date_obj));
02032        memset(intern, 0, sizeof(php_date_obj));
02033        if (ptr) {
02034               *ptr = intern;
02035        }
02036        
02037        zend_object_std_init(&intern->std, class_type TSRMLS_CC);
02038        zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
02039        
02040        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);
02041        retval.handlers = &date_object_handlers_date;
02042        
02043        return retval;
02044 }
02045 
02046 static zend_object_value date_object_new_date(zend_class_entry *class_type TSRMLS_DC)
02047 {
02048        return date_object_new_date_ex(class_type, NULL TSRMLS_CC);
02049 }
02050 
02051 static zend_object_value date_object_clone_date(zval *this_ptr TSRMLS_DC)
02052 {
02053        php_date_obj *new_obj = NULL;
02054        php_date_obj *old_obj = (php_date_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
02055        zend_object_value new_ov = date_object_new_date_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
02056        
02057        zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
02058        if (!old_obj->time) {
02059               return new_ov;
02060        }
02061        
02062        /* this should probably moved to a new `timelib_time *timelime_time_clone(timelib_time *)` */
02063        new_obj->time = timelib_time_ctor();
02064        *new_obj->time = *old_obj->time;
02065        if (old_obj->time->tz_abbr) {
02066               new_obj->time->tz_abbr = strdup(old_obj->time->tz_abbr);
02067        }
02068        if (old_obj->time->tz_info) {
02069               new_obj->time->tz_info = old_obj->time->tz_info;
02070        }
02071        
02072        return new_ov;
02073 }
02074 
02075 static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC)
02076 {
02077        if (Z_TYPE_P(d1) == IS_OBJECT && Z_TYPE_P(d2) == IS_OBJECT &&
02078               instanceof_function(Z_OBJCE_P(d1), date_ce_date TSRMLS_CC) &&
02079               instanceof_function(Z_OBJCE_P(d2), date_ce_date TSRMLS_CC)) {
02080               php_date_obj *o1 = zend_object_store_get_object(d1 TSRMLS_CC);
02081               php_date_obj *o2 = zend_object_store_get_object(d2 TSRMLS_CC);
02082               
02083               if (!o1->time->sse_uptodate) {
02084                      timelib_update_ts(o1->time, o1->time->tz_info);
02085               }
02086               if (!o2->time->sse_uptodate) {
02087                      timelib_update_ts(o2->time, o2->time->tz_info);
02088               }
02089               
02090               return (o1->time->sse == o2->time->sse) ? 0 : ((o1->time->sse < o2->time->sse) ? -1 : 1);
02091        }
02092        
02093        return 1;
02094 }
02095 
02096 static HashTable *date_object_get_properties(zval *object TSRMLS_DC)
02097 {
02098        HashTable *props;
02099        zval *zv;
02100        php_date_obj     *dateobj;
02101 
02102 
02103        dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
02104 
02105        props = zend_std_get_properties(object TSRMLS_CC);
02106 
02107        if (!dateobj->time || GC_G(gc_active)) {
02108               return props;
02109        }
02110 
02111        /* first we add the date and time in ISO format */
02112        MAKE_STD_ZVAL(zv);
02113        ZVAL_STRING(zv, date_format("Y-m-d H:i:s", 12, dateobj->time, 1), 0);
02114        zend_hash_update(props, "date", 5, &zv, sizeof(zval), NULL);
02115 
02116        /* then we add the timezone name (or similar) */
02117        if (dateobj->time->is_localtime) {
02118               MAKE_STD_ZVAL(zv);
02119               ZVAL_LONG(zv, dateobj->time->zone_type);
02120               zend_hash_update(props, "timezone_type", 14, &zv, sizeof(zval), NULL);
02121 
02122               MAKE_STD_ZVAL(zv);
02123               switch (dateobj->time->zone_type) {
02124                      case TIMELIB_ZONETYPE_ID:
02125                             ZVAL_STRING(zv, dateobj->time->tz_info->name, 1);
02126                             break;
02127                      case TIMELIB_ZONETYPE_OFFSET: {
02128                             char *tmpstr = emalloc(sizeof("UTC+05:00"));
02129                             timelib_sll utc_offset = dateobj->time->z;
02130 
02131                             snprintf(tmpstr, sizeof("+05:00"), "%c%02d:%02d",
02132                                    utc_offset > 0 ? '-' : '+',
02133                                    abs(utc_offset / 60),
02134                                    abs((utc_offset % 60)));
02135 
02136                             ZVAL_STRING(zv, tmpstr, 0);
02137                             }
02138                             break;
02139                      case TIMELIB_ZONETYPE_ABBR:
02140                             ZVAL_STRING(zv, dateobj->time->tz_abbr, 1);
02141                             break;
02142               }
02143               zend_hash_update(props, "timezone", 9, &zv, sizeof(zval), NULL);
02144        }
02145 
02146        return props;
02147 }
02148 
02149 static inline zend_object_value date_object_new_timezone_ex(zend_class_entry *class_type, php_timezone_obj **ptr TSRMLS_DC)
02150 {
02151        php_timezone_obj *intern;
02152        zend_object_value retval;
02153        zval *tmp;
02154 
02155        intern = emalloc(sizeof(php_timezone_obj));
02156        memset(intern, 0, sizeof(php_timezone_obj));
02157        if (ptr) {
02158               *ptr = intern;
02159        }
02160 
02161        zend_object_std_init(&intern->std, class_type TSRMLS_CC);
02162        zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
02163        
02164        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);
02165        retval.handlers = &date_object_handlers_timezone;
02166        
02167        return retval;
02168 }
02169 
02170 static zend_object_value date_object_new_timezone(zend_class_entry *class_type TSRMLS_DC)
02171 {
02172        return date_object_new_timezone_ex(class_type, NULL TSRMLS_CC);
02173 }
02174 
02175 static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC)
02176 {
02177        php_timezone_obj *new_obj = NULL;
02178        php_timezone_obj *old_obj = (php_timezone_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
02179        zend_object_value new_ov = date_object_new_timezone_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
02180        
02181        zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
02182        if (!old_obj->initialized) {
02183               return new_ov;
02184        }
02185        
02186        new_obj->type = old_obj->type;
02187        new_obj->initialized = 1;
02188        switch (new_obj->type) {
02189               case TIMELIB_ZONETYPE_ID:
02190                      new_obj->tzi.tz = old_obj->tzi.tz;
02191                      break;
02192               case TIMELIB_ZONETYPE_OFFSET:
02193                      new_obj->tzi.utc_offset = old_obj->tzi.utc_offset;
02194                      break;
02195               case TIMELIB_ZONETYPE_ABBR:
02196                      new_obj->tzi.z.utc_offset = old_obj->tzi.z.utc_offset;
02197                      new_obj->tzi.z.dst        = old_obj->tzi.z.dst;
02198                      new_obj->tzi.z.abbr       = old_obj->tzi.z.abbr;
02199                      break;
02200        }
02201        
02202        return new_ov;
02203 }
02204 
02205 static inline zend_object_value date_object_new_interval_ex(zend_class_entry *class_type, php_interval_obj **ptr TSRMLS_DC)
02206 {
02207        php_interval_obj *intern;
02208        zend_object_value retval;
02209        zval *tmp;
02210 
02211        intern = emalloc(sizeof(php_interval_obj));
02212        memset(intern, 0, sizeof(php_interval_obj));
02213        if (ptr) {
02214               *ptr = intern;
02215        }
02216 
02217        zend_object_std_init(&intern->std, class_type TSRMLS_CC);
02218        zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
02219        
02220        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);
02221        retval.handlers = &date_object_handlers_interval;
02222        
02223        return retval;
02224 }
02225 
02226 static zend_object_value date_object_new_interval(zend_class_entry *class_type TSRMLS_DC)
02227 {
02228        return date_object_new_interval_ex(class_type, NULL TSRMLS_CC);
02229 }
02230 
02231 static zend_object_value date_object_clone_interval(zval *this_ptr TSRMLS_DC)
02232 {
02233        php_interval_obj *new_obj = NULL;
02234        php_interval_obj *old_obj = (php_interval_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
02235        zend_object_value new_ov = date_object_new_interval_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
02236        
02237        zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
02238 
02240        return new_ov;
02241 }
02242 
02243 static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC)
02244 {
02245        HashTable *props;
02246        zval *zv;
02247        php_interval_obj     *intervalobj;
02248 
02249 
02250        intervalobj = (php_interval_obj *) zend_object_store_get_object(object TSRMLS_CC);
02251 
02252        props = zend_std_get_properties(object TSRMLS_CC);
02253 
02254        if (!intervalobj->initialized || GC_G(gc_active)) {
02255               return props;
02256        }
02257 
02258 #define PHP_DATE_INTERVAL_ADD_PROPERTY(n,f) \
02259        MAKE_STD_ZVAL(zv); \
02260        ZVAL_LONG(zv, intervalobj->diff->f); \
02261        zend_hash_update(props, n, strlen(n) + 1, &zv, sizeof(zval), NULL);
02262 
02263        PHP_DATE_INTERVAL_ADD_PROPERTY("y", y);
02264        PHP_DATE_INTERVAL_ADD_PROPERTY("m", m);
02265        PHP_DATE_INTERVAL_ADD_PROPERTY("d", d);
02266        PHP_DATE_INTERVAL_ADD_PROPERTY("h", h);
02267        PHP_DATE_INTERVAL_ADD_PROPERTY("i", i);
02268        PHP_DATE_INTERVAL_ADD_PROPERTY("s", s);
02269        PHP_DATE_INTERVAL_ADD_PROPERTY("invert", invert);
02270        if (intervalobj->diff->days != -99999) {
02271               PHP_DATE_INTERVAL_ADD_PROPERTY("days", days);
02272        } else {
02273               MAKE_STD_ZVAL(zv);
02274               ZVAL_FALSE(zv);
02275               zend_hash_update(props, "days", 5, &zv, sizeof(zval), NULL);
02276        }
02277 
02278        return props;
02279 }
02280 
02281 static inline zend_object_value date_object_new_period_ex(zend_class_entry *class_type, php_period_obj **ptr TSRMLS_DC)
02282 {
02283        php_period_obj *intern;
02284        zend_object_value retval;
02285        zval *tmp;
02286 
02287        intern = emalloc(sizeof(php_period_obj));
02288        memset(intern, 0, sizeof(php_period_obj));
02289        if (ptr) {
02290               *ptr = intern;
02291        }
02292 
02293        zend_object_std_init(&intern->std, class_type TSRMLS_CC);
02294        zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
02295        
02296        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);
02297        retval.handlers = &date_object_handlers_period;
02298        
02299        return retval;
02300 }
02301 
02302 static zend_object_value date_object_new_period(zend_class_entry *class_type TSRMLS_DC)
02303 {
02304        return date_object_new_period_ex(class_type, NULL TSRMLS_CC);
02305 }
02306 
02307 static zend_object_value date_object_clone_period(zval *this_ptr TSRMLS_DC)
02308 {
02309        php_period_obj *new_obj = NULL;
02310        php_period_obj *old_obj = (php_period_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
02311        zend_object_value new_ov = date_object_new_period_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
02312        
02313        zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
02314 
02316        return new_ov;
02317 }
02318 
02319 static void date_object_free_storage_date(void *object TSRMLS_DC)
02320 {
02321        php_date_obj *intern = (php_date_obj *)object;
02322 
02323        if (intern->time) {
02324               timelib_time_dtor(intern->time);
02325        }
02326 
02327        zend_object_std_dtor(&intern->std TSRMLS_CC);
02328        efree(object);
02329 }
02330 
02331 static void date_object_free_storage_timezone(void *object TSRMLS_DC)
02332 {
02333        php_timezone_obj *intern = (php_timezone_obj *)object;
02334 
02335        if (intern->type == TIMELIB_ZONETYPE_ABBR) {
02336               free(intern->tzi.z.abbr);
02337        }
02338        zend_object_std_dtor(&intern->std TSRMLS_CC);
02339        efree(object);
02340 }
02341 
02342 static void date_object_free_storage_interval(void *object TSRMLS_DC)
02343 {
02344        php_interval_obj *intern = (php_interval_obj *)object;
02345 
02346        timelib_rel_time_dtor(intern->diff);
02347        zend_object_std_dtor(&intern->std TSRMLS_CC);
02348        efree(object);
02349 }
02350 
02351 static void date_object_free_storage_period(void *object TSRMLS_DC)
02352 {
02353        php_period_obj *intern = (php_period_obj *)object;
02354 
02355        if (intern->start) {
02356               timelib_time_dtor(intern->start);
02357        }
02358 
02359        if (intern->current) {
02360               timelib_time_dtor(intern->current);
02361        }
02362 
02363        if (intern->end) {
02364               timelib_time_dtor(intern->end);
02365        }
02366 
02367        timelib_rel_time_dtor(intern->interval);
02368        zend_object_std_dtor(&intern->std TSRMLS_CC);
02369        efree(object);
02370 }
02371 
02372 /* Advanced Interface */
02373 PHPAPI zval *php_date_instantiate(zend_class_entry *pce, zval *object TSRMLS_DC)
02374 {
02375        Z_TYPE_P(object) = IS_OBJECT;
02376        object_init_ex(object, pce);
02377        Z_SET_REFCOUNT_P(object, 1);
02378        Z_UNSET_ISREF_P(object);
02379        return object;
02380 }
02381 
02382 /* Helper function used to store the latest found warnings and errors while
02383  * parsing, from either strtotime or parse_from_format. */
02384 static void update_errors_warnings(timelib_error_container *last_errors TSRMLS_DC)
02385 {
02386        if (DATEG(last_errors)) {
02387               timelib_error_container_dtor(DATEG(last_errors));
02388               DATEG(last_errors) = NULL;
02389        }
02390        DATEG(last_errors) = last_errors;
02391 }
02392 
02393 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)
02394 {
02395        timelib_time   *now;
02396        timelib_tzinfo *tzi = NULL;
02397        timelib_error_container *err = NULL;
02398        int type = TIMELIB_ZONETYPE_ID, new_dst;
02399        char *new_abbr;
02400        timelib_sll     new_offset;
02401        
02402        if (dateobj->time) {
02403               timelib_time_dtor(dateobj->time);
02404        }
02405        if (format) {
02406               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);
02407        } else {
02408               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);
02409        }
02410 
02411        /* update last errors and warnings */
02412        update_errors_warnings(err TSRMLS_CC);
02413 
02414 
02415        if (ctor && err && err->error_count) {
02416               /* spit out the first library error message, at least */
02417               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse time string (%s) at position %d (%c): %s", time_str,
02418                      err->error_messages[0].position, err->error_messages[0].character, err->error_messages[0].message);
02419        }
02420        if (err && err->error_count) {
02421               return 0;
02422        }
02423 
02424        if (timezone_object) {
02425               php_timezone_obj *tzobj;
02426 
02427               tzobj = (php_timezone_obj *) zend_object_store_get_object(timezone_object TSRMLS_CC);
02428               switch (tzobj->type) {
02429                      case TIMELIB_ZONETYPE_ID:
02430                             tzi = tzobj->tzi.tz;
02431                             break;
02432                      case TIMELIB_ZONETYPE_OFFSET:
02433                             new_offset = tzobj->tzi.utc_offset;
02434                             break;
02435                      case TIMELIB_ZONETYPE_ABBR:
02436                             new_offset = tzobj->tzi.z.utc_offset;
02437                             new_dst    = tzobj->tzi.z.dst;
02438                             new_abbr   = strdup(tzobj->tzi.z.abbr);
02439                             break;
02440               }
02441               type = tzobj->type;
02442        } else if (dateobj->time->tz_info) {
02443               tzi = dateobj->time->tz_info;
02444        } else {
02445               tzi = get_timezone_info(TSRMLS_C);
02446        }
02447 
02448        now = timelib_time_ctor();
02449        now->zone_type = type;
02450        switch (type) {
02451               case TIMELIB_ZONETYPE_ID:
02452                      now->tz_info = tzi;
02453                      break;
02454               case TIMELIB_ZONETYPE_OFFSET:
02455                      now->z = new_offset;
02456                      break;
02457               case TIMELIB_ZONETYPE_ABBR:
02458                      now->z = new_offset;
02459                      now->dst = new_dst;
02460                      now->tz_abbr = new_abbr;
02461                      break;
02462        }
02463        timelib_unixtime2local(now, (timelib_sll) time(NULL));
02464 
02465        timelib_fill_holes(dateobj->time, now, TIMELIB_NO_CLONE);
02466        timelib_update_ts(dateobj->time, tzi);
02467 
02468        dateobj->time->have_relative = 0;
02469 
02470        timelib_time_dtor(now);
02471 
02472        return 1;
02473 }
02474 
02475 /* {{{ proto DateTime date_create([string time[, DateTimeZone object]])
02476    Returns new DateTime object
02477 */
02478 PHP_FUNCTION(date_create)
02479 {
02480        zval           *timezone_object = NULL;
02481        char           *time_str = NULL;
02482        int             time_str_len = 0;
02483 
02484        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sO!", &time_str, &time_str_len, &timezone_object, date_ce_timezone) == FAILURE) {
02485               RETURN_FALSE;
02486        }
02487 
02488        php_date_instantiate(date_ce_date, return_value TSRMLS_CC);
02489        if (!php_date_initialize(zend_object_store_get_object(return_value TSRMLS_CC), time_str, time_str_len, NULL, timezone_object, 0 TSRMLS_CC)) {
02490               RETURN_FALSE;
02491        }
02492 }
02493 /* }}} */
02494 
02495 /* {{{ proto DateTime date_create_from_format(string format, string time[, DateTimeZone object])
02496    Returns new DateTime object formatted according to the specified format
02497 */
02498 PHP_FUNCTION(date_create_from_format)
02499 {
02500        zval           *timezone_object = NULL;
02501        char           *time_str = NULL, *format_str = NULL;
02502        int             time_str_len = 0, format_str_len = 0;
02503 
02504        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) {
02505               RETURN_FALSE;
02506        }
02507 
02508        php_date_instantiate(date_ce_date, return_value TSRMLS_CC);
02509        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)) {
02510               RETURN_FALSE;
02511        }
02512 }
02513 /* }}} */
02514 
02515 /* {{{ proto DateTime::__construct([string time[, DateTimeZone object]])
02516    Creates new DateTime object
02517 */
02518 PHP_METHOD(DateTime, __construct)
02519 {
02520        zval *timezone_object = NULL;
02521        char *time_str = NULL;
02522        int time_str_len = 0;
02523        zend_error_handling error_handling;
02524 
02525        zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
02526        if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sO!", &time_str, &time_str_len, &timezone_object, date_ce_timezone)) {
02527               php_date_initialize(zend_object_store_get_object(getThis() TSRMLS_CC), time_str, time_str_len, NULL, timezone_object, 1 TSRMLS_CC);
02528        }
02529        zend_restore_error_handling(&error_handling TSRMLS_CC);
02530 }
02531 /* }}} */
02532 
02533 static int php_date_initialize_from_hash(zval **return_value, php_date_obj **dateobj, HashTable *myht TSRMLS_DC)
02534 {
02535        zval            **z_date = NULL;
02536        zval            **z_timezone = NULL;
02537        zval            **z_timezone_type = NULL;
02538        zval             *tmp_obj = NULL;
02539        timelib_tzinfo   *tzi;
02540        php_timezone_obj *tzobj;
02541 
02542        if (zend_hash_find(myht, "date", 5, (void**) &z_date) == SUCCESS) {
02543               convert_to_string(*z_date);
02544               if (zend_hash_find(myht, "timezone_type", 14, (void**) &z_timezone_type) == SUCCESS) {
02545                      convert_to_long(*z_timezone_type);
02546                      if (zend_hash_find(myht, "timezone", 9, (void**) &z_timezone) == SUCCESS) {
02547                             convert_to_string(*z_timezone);
02548 
02549                             switch (Z_LVAL_PP(z_timezone_type)) {
02550                                    case TIMELIB_ZONETYPE_OFFSET:
02551                                    case TIMELIB_ZONETYPE_ABBR: {
02552                                           char *tmp = emalloc(Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 2);
02553                                           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));
02554                                           php_date_initialize(*dateobj, tmp, Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 1, NULL, NULL, 0 TSRMLS_CC);
02555                                           efree(tmp);
02556                                           return 1;
02557                                    }
02558 
02559                                    case TIMELIB_ZONETYPE_ID:
02560                                           convert_to_string(*z_timezone);
02561 
02562                                           tzi = php_date_parse_tzfile(Z_STRVAL_PP(z_timezone), DATE_TIMEZONEDB TSRMLS_CC);
02563 
02564                                           ALLOC_INIT_ZVAL(tmp_obj);
02565                                           tzobj = zend_object_store_get_object(php_date_instantiate(date_ce_timezone, tmp_obj TSRMLS_CC) TSRMLS_CC);
02566                                           tzobj->type = TIMELIB_ZONETYPE_ID;
02567                                           tzobj->tzi.tz = tzi;
02568                                           tzobj->initialized = 1;
02569 
02570                                           php_date_initialize(*dateobj, Z_STRVAL_PP(z_date), Z_STRLEN_PP(z_date), NULL, tmp_obj, 0 TSRMLS_CC);
02571                                           zval_ptr_dtor(&tmp_obj);
02572                                           return 1;
02573                             }
02574                      }
02575               }
02576        }
02577        return 0;
02578 }
02579 
02580 /* {{{ proto DateTime::__set_state()
02581 */
02582 PHP_METHOD(DateTime, __set_state)
02583 {
02584        php_date_obj     *dateobj;
02585        zval             *array;
02586        HashTable        *myht;
02587 
02588        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
02589               RETURN_FALSE;
02590        }
02591 
02592        myht = HASH_OF(array);
02593 
02594        php_date_instantiate(date_ce_date, return_value TSRMLS_CC);
02595        dateobj = (php_date_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
02596        php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC);
02597 }
02598 /* }}} */
02599 
02600 /* {{{ proto DateTime::__wakeup()
02601 */
02602 PHP_METHOD(DateTime, __wakeup)
02603 {
02604        zval             *object = getThis();
02605        php_date_obj     *dateobj;
02606        HashTable        *myht;
02607 
02608        dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
02609 
02610        myht = Z_OBJPROP_P(object);
02611 
02612        php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC);
02613 }
02614 /* }}} */
02615 
02616 /* Helper function used to add an associative array of warnings and errors to a zval */
02617 static void zval_from_error_container(zval *z, timelib_error_container *error)
02618 {
02619        int   i;
02620        zval *element;
02621 
02622        add_assoc_long(z, "warning_count", error->warning_count);
02623        MAKE_STD_ZVAL(element);
02624        array_init(element);
02625        for (i = 0; i < error->warning_count; i++) {
02626               add_index_string(element, error->warning_messages[i].position, error->warning_messages[i].message, 1);
02627        }
02628        add_assoc_zval(z, "warnings", element);
02629 
02630        add_assoc_long(z, "error_count", error->error_count);
02631        MAKE_STD_ZVAL(element);
02632        array_init(element);
02633        for (i = 0; i < error->error_count; i++) {
02634               add_index_string(element, error->error_messages[i].position, error->error_messages[i].message, 1);
02635        }
02636        add_assoc_zval(z, "errors", element);
02637 }
02638 
02639 /* {{{ proto array date_get_last_errors()
02640    Returns the warnings and errors found while parsing a date/time string.
02641 */
02642 PHP_FUNCTION(date_get_last_errors)
02643 {
02644        if (DATEG(last_errors)) {
02645               array_init(return_value);
02646               zval_from_error_container(return_value, DATEG(last_errors));
02647        } else {
02648               RETURN_FALSE;
02649        }
02650 }
02651 /* }}} */
02652 
02653 void php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAMETERS, timelib_time *parsed_time, struct timelib_error_container *error)
02654 {
02655        zval *element;
02656 
02657        array_init(return_value);
02658 #define PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(name, elem) \
02659        if (parsed_time->elem == -99999) {               \
02660               add_assoc_bool(return_value, #name, 0); \
02661        } else {                                       \
02662               add_assoc_long(return_value, #name, parsed_time->elem); \
02663        }
02664        PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(year,      y);
02665        PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(month,     m);
02666        PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(day,       d);
02667        PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(hour,      h);
02668        PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(minute,    i);
02669        PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(second,    s);
02670        
02671        if (parsed_time->f == -99999) {
02672               add_assoc_bool(return_value, "fraction", 0);
02673        } else {
02674               add_assoc_double(return_value, "fraction", parsed_time->f);
02675        }
02676 
02677        zval_from_error_container(return_value, error);
02678 
02679        timelib_error_container_dtor(error);
02680 
02681        add_assoc_bool(return_value, "is_localtime", parsed_time->is_localtime);
02682 
02683        if (parsed_time->is_localtime) {
02684               PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone_type, zone_type);
02685               switch (parsed_time->zone_type) {
02686                      case TIMELIB_ZONETYPE_OFFSET:
02687                             PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone, z);
02688                             add_assoc_bool(return_value, "is_dst", parsed_time->dst);
02689                             break;
02690                      case TIMELIB_ZONETYPE_ID:
02691                             if (parsed_time->tz_abbr) {
02692                                    add_assoc_string(return_value, "tz_abbr", parsed_time->tz_abbr, 1);
02693                             }
02694                             if (parsed_time->tz_info) {
02695                                    add_assoc_string(return_value, "tz_id", parsed_time->tz_info->name, 1);
02696                             }
02697                             break;
02698                      case TIMELIB_ZONETYPE_ABBR:
02699                             PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone, z);
02700                             add_assoc_bool(return_value, "is_dst", parsed_time->dst);
02701                             add_assoc_string(return_value, "tz_abbr", parsed_time->tz_abbr, 1);
02702                             break;
02703               }
02704        }
02705        if (parsed_time->have_relative) {
02706               MAKE_STD_ZVAL(element);
02707               array_init(element);
02708               add_assoc_long(element, "year",   parsed_time->relative.y);
02709               add_assoc_long(element, "month",  parsed_time->relative.m);
02710               add_assoc_long(element, "day",    parsed_time->relative.d);
02711               add_assoc_long(element, "hour",   parsed_time->relative.h);
02712               add_assoc_long(element, "minute", parsed_time->relative.i);
02713               add_assoc_long(element, "second", parsed_time->relative.s);
02714               if (parsed_time->relative.have_weekday_relative) {
02715                      add_assoc_long(element, "weekday", parsed_time->relative.weekday);
02716               }
02717               if (parsed_time->relative.have_special_relative && (parsed_time->relative.special.type == TIMELIB_SPECIAL_WEEKDAY)) {
02718                      add_assoc_long(element, "weekdays", parsed_time->relative.special.amount);
02719               }
02720               if (parsed_time->relative.first_last_day_of) {
02721                      add_assoc_bool(element, parsed_time->relative.first_last_day_of == 1 ? "first_day_of_month" : "last_day_of_month", 1);
02722               }
02723               add_assoc_zval(return_value, "relative", element);
02724        }
02725        timelib_time_dtor(parsed_time);
02726 }
02727 
02728 /* {{{ proto array date_parse(string date)
02729    Returns associative array with detailed info about given date
02730 */
02731 PHP_FUNCTION(date_parse)
02732 {
02733        char                           *date;
02734        int                             date_len;
02735        struct timelib_error_container *error;
02736        timelib_time                   *parsed_time;
02737        
02738        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &date, &date_len) == FAILURE) {
02739               RETURN_FALSE;
02740        }
02741 
02742        parsed_time = timelib_strtotime(date, date_len, &error, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
02743        php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAM_PASSTHRU, parsed_time, error);
02744 }
02745 /* }}} */
02746 
02747 /* {{{ proto array date_parse_from_format(string format, string date)
02748    Returns associative array with detailed info about given date
02749 */
02750 PHP_FUNCTION(date_parse_from_format)
02751 {
02752        char                           *date, *format;
02753        int                             date_len, format_len;
02754        struct timelib_error_container *error;
02755        timelib_time                   *parsed_time;
02756        
02757        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &format, &format_len, &date, &date_len) == FAILURE) {
02758               RETURN_FALSE;
02759        }
02760 
02761        parsed_time = timelib_parse_from_format(format, date, date_len, &error, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
02762        php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAM_PASSTHRU, parsed_time, error);
02763 }
02764 /* }}} */
02765 
02766 /* {{{ proto string date_format(DateTime object, string format)
02767    Returns date formatted according to given format
02768 */
02769 PHP_FUNCTION(date_format)
02770 {
02771        zval         *object;
02772        php_date_obj *dateobj;
02773        char         *format;
02774        int           format_len;
02775 
02776        if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_date, &format, &format_len) == FAILURE) {
02777               RETURN_FALSE;
02778        }
02779        dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
02780        DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
02781        RETURN_STRING(date_format(format, format_len, dateobj->time, dateobj->time->is_localtime), 0);
02782 }
02783 /* }}} */
02784 
02785 /* {{{ proto DateTime date_modify(DateTime object, string modify)
02786    Alters the timestamp.
02787 */
02788 PHP_FUNCTION(date_modify)
02789 {
02790        zval         *object;
02791        php_date_obj *dateobj;
02792        char         *modify;
02793        int           modify_len;
02794        timelib_time *tmp_time;
02795        timelib_error_container *err = NULL;
02796 
02797        if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_date, &modify, &modify_len) == FAILURE) {
02798               RETURN_FALSE;
02799        }
02800        dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
02801        DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
02802 
02803        tmp_time = timelib_strtotime(modify, modify_len, &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
02804 
02805        /* update last errors and warnings */
02806        update_errors_warnings(err TSRMLS_CC);
02807        if (err && err->error_count) {
02808               /* spit out the first library error message, at least */
02809               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse time string (%s) at position %d (%c): %s", modify,
02810                      err->error_messages[0].position, err->error_messages[0].character, err->error_messages[0].message);
02811               timelib_time_dtor(tmp_time);
02812               RETURN_FALSE;
02813        }
02814 
02815        memcpy(&dateobj->time->relative, &tmp_time->relative, sizeof(struct timelib_rel_time));
02816        dateobj->time->have_relative = tmp_time->have_relative;
02817        dateobj->time->sse_uptodate = 0;
02818 
02819        if (tmp_time->y != -99999) {
02820               dateobj->time->y = tmp_time->y;
02821        }
02822        if (tmp_time->m != -99999) {
02823               dateobj->time->m = tmp_time->m;
02824        }
02825        if (tmp_time->d != -99999) {
02826               dateobj->time->d = tmp_time->d;
02827        }
02828 
02829        if (tmp_time->h != -99999) {
02830               dateobj->time->h = tmp_time->h;
02831               if (tmp_time->i != -99999) {
02832                      dateobj->time->i = tmp_time->i;
02833                      if (tmp_time->s != -99999) {
02834                             dateobj->time->s = tmp_time->s;
02835                      } else {
02836                             dateobj->time->s = 0;
02837                      }
02838               } else {
02839                      dateobj->time->i = 0;
02840                      dateobj->time->s = 0;
02841               }
02842        }
02843        timelib_time_dtor(tmp_time);
02844 
02845        timelib_update_ts(dateobj->time, NULL);
02846        timelib_update_from_sse(dateobj->time);
02847        dateobj->time->have_relative = 0;
02848 
02849        RETURN_ZVAL(object, 1, 0);
02850 }
02851 /* }}} */
02852 
02853 /* {{{ proto DateTime date_add(DateTime object, DateInterval interval)
02854    Adds an interval to the current date in object.
02855 */
02856 PHP_FUNCTION(date_add)
02857 {
02858        zval         *object, *interval;
02859        php_date_obj *dateobj;
02860        php_interval_obj *intobj;
02861        int               bias = 1;
02862 
02863        if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) {
02864               RETURN_FALSE;
02865        }
02866        dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
02867        DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
02868        intobj = (php_interval_obj *) zend_object_store_get_object(interval TSRMLS_CC);
02869        DATE_CHECK_INITIALIZED(intobj->initialized, DateInterval);
02870 
02871 
02872        if (intobj->diff->have_weekday_relative || intobj->diff->have_special_relative) {
02873               memcpy(&dateobj->time->relative, intobj->diff, sizeof(struct timelib_rel_time));
02874        } else {
02875               if (intobj->diff->invert) {
02876                      bias = -1;
02877               }
02878               memset(&dateobj->time->relative, 0, sizeof(struct timelib_rel_time));
02879               dateobj->time->relative.y = intobj->diff->y * bias;
02880               dateobj->time->relative.m = intobj->diff->m * bias;
02881               dateobj->time->relative.d = intobj->diff->d * bias;
02882               dateobj->time->relative.h = intobj->diff->h * bias;
02883               dateobj->time->relative.i = intobj->diff->i * bias;
02884               dateobj->time->relative.s = intobj->diff->s * bias;
02885        }
02886        dateobj->time->have_relative = 1;
02887        dateobj->time->sse_uptodate = 0;
02888 
02889        timelib_update_ts(dateobj->time, NULL);
02890        timelib_update_from_sse(dateobj->time);
02891        dateobj->time->have_relative = 0;
02892 
02893        RETURN_ZVAL(object, 1, 0);
02894 }
02895 /* }}} */
02896 
02897 /* {{{ proto DateTime date_sub(DateTime object, DateInterval interval)
02898    Subtracts an interval to the current date in object.
02899 */
02900 PHP_FUNCTION(date_sub)
02901 {
02902        zval         *object, *interval;
02903        php_date_obj *dateobj;
02904        php_interval_obj *intobj;
02905        int               bias = 1;
02906 
02907        if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) {
02908               RETURN_FALSE;
02909        }
02910        dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
02911        DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
02912        intobj = (php_interval_obj *) zend_object_store_get_object(interval TSRMLS_CC);
02913        DATE_CHECK_INITIALIZED(intobj->initialized, DateInterval);
02914 
02915        if (intobj->diff->have_special_relative) {
02916               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Only non-special relative time specifications are supported for subtraction");
02917               return;
02918        }
02919 
02920        if (intobj->diff->invert) {
02921               bias = -1;
02922        }
02923 
02924        memset(&dateobj->time->relative, 0, sizeof(struct timelib_rel_time));
02925        dateobj->time->relative.y = 0 - (intobj->diff->y * bias);
02926        dateobj->time->relative.m = 0 - (intobj->diff->m * bias);
02927        dateobj->time->relative.d = 0 - (intobj->diff->d * bias);
02928        dateobj->time->relative.h = 0 - (intobj->diff->h * bias);
02929        dateobj->time->relative.i = 0 - (intobj->diff->i * bias);
02930        dateobj->time->relative.s = 0 - (intobj->diff->s * bias);
02931        dateobj->time->have_relative = 1;
02932        dateobj->time->sse_uptodate = 0;
02933 
02934        timelib_update_ts(dateobj->time, NULL);
02935        timelib_update_from_sse(dateobj->time);
02936 
02937        dateobj->time->have_relative = 0;
02938 
02939        RETURN_ZVAL(object, 1, 0);
02940 }
02941 /* }}} */
02942 
02943 /* {{{ proto DateTimeZone date_timezone_get(DateTime object)
02944    Return new DateTimeZone object relative to give DateTime
02945 */
02946 PHP_FUNCTION(date_timezone_get)
02947 {
02948        zval             *object;
02949        php_date_obj     *dateobj;
02950        php_timezone_obj *tzobj;
02951 
02952        if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_date) == FAILURE) {
02953               RETURN_FALSE;
02954        }
02955        dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
02956        DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
02957        if (dateobj->time->is_localtime/* && dateobj->time->tz_info*/) {
02958               php_date_instantiate(date_ce_timezone, return_value TSRMLS_CC);
02959               tzobj = (php_timezone_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
02960               tzobj->initialized = 1;
02961               tzobj->type = dateobj->time->zone_type;
02962               switch (dateobj->time->zone_type) {
02963                      case TIMELIB_ZONETYPE_ID:
02964                             tzobj->tzi.tz = dateobj->time->tz_info;
02965                             break;
02966                      case TIMELIB_ZONETYPE_OFFSET:
02967                             tzobj->tzi.utc_offset = dateobj->time->z;
02968                             break;
02969                      case TIMELIB_ZONETYPE_ABBR:
02970                             tzobj->tzi.z.utc_offset = dateobj->time->z;
02971                             tzobj->tzi.z.dst = dateobj->time->dst;
02972                             tzobj->tzi.z.abbr = strdup(dateobj->time->tz_abbr);
02973                             break;
02974               }
02975        } else {
02976               RETURN_FALSE;
02977        }
02978 }
02979 /* }}} */
02980 
02981 /* {{{ proto DateTime date_timezone_set(DateTime object, DateTimeZone object)
02982    Sets the timezone for the DateTime object.
02983 */
02984 PHP_FUNCTION(date_timezone_set)
02985 {
02986        zval             *object;
02987        zval             *timezone_object;
02988        php_date_obj     *dateobj;
02989        php_timezone_obj *tzobj;
02990 
02991        if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &timezone_object, date_ce_timezone) == FAILURE) {
02992               RETURN_FALSE;
02993        }
02994        dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
02995        DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
02996        tzobj = (php_timezone_obj *) zend_object_store_get_object(timezone_object TSRMLS_CC);
02997        if (tzobj->type != TIMELIB_ZONETYPE_ID) {
02998               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can only do this for zones with ID for now");
02999               return;
03000        }
03001        timelib_set_timezone(dateobj->time, tzobj->tzi.tz);
03002        timelib_unixtime2local(dateobj->time, dateobj->time->sse);
03003 
03004        RETURN_ZVAL(object, 1, 0);
03005 }
03006 /* }}} */
03007 
03008 /* {{{ proto long date_offset_get(DateTime object)
03009    Returns the DST offset.
03010 */
03011 PHP_FUNCTION(date_offset_get)
03012 {
03013        zval                *object;
03014        php_date_obj        *dateobj;
03015        timelib_time_offset *offset;
03016 
03017        if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_date) == FAILURE) {
03018               RETURN_FALSE;
03019        }
03020        dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
03021        DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
03022        if (dateobj->time->is_localtime/* && dateobj->time->tz_info*/) {
03023               switch (dateobj->time->zone_type) {
03024                      case TIMELIB_ZONETYPE_ID:
03025                             offset = timelib_get_time_zone_info(dateobj->time->sse, dateobj->time->tz_info);
03026                             RETVAL_LONG(offset->offset);
03027                             timelib_time_offset_dtor(offset);
03028                             break;
03029                      case TIMELIB_ZONETYPE_OFFSET:
03030                             RETVAL_LONG(dateobj->time->z * -60);
03031                             break;
03032                      case TIMELIB_ZONETYPE_ABBR:
03033                             RETVAL_LONG((dateobj->time->z - (60 * dateobj->time->dst)) * -60);
03034                             break;
03035               }
03036               return;
03037        } else {
03038               RETURN_LONG(0);
03039        }
03040 }
03041 /* }}} */
03042 
03043 /* {{{ proto DateTime date_time_set(DateTime object, long hour, long minute[, long second])
03044    Sets the time.
03045 */
03046 PHP_FUNCTION(date_time_set)
03047 {
03048        zval         *object;
03049        php_date_obj *dateobj;
03050        long          h, i, s = 0;
03051 
03052        if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_date, &h, &i, &s) == FAILURE) {
03053               RETURN_FALSE;
03054        }
03055        dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
03056        DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
03057        dateobj->time->h = h;
03058        dateobj->time->i = i;
03059        dateobj->time->s = s;
03060        timelib_update_ts(dateobj->time, NULL);
03061 
03062        RETURN_ZVAL(object, 1, 0);
03063 }
03064 /* }}} */
03065 
03066 /* {{{ proto DateTime date_date_set(DateTime object, long year, long month, long day)
03067    Sets the date.
03068 */
03069 PHP_FUNCTION(date_date_set)
03070 {
03071        zval         *object;
03072        php_date_obj *dateobj;
03073        long          y, m, d;
03074 
03075        if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Olll", &object, date_ce_date, &y, &m, &d) == FAILURE) {
03076               RETURN_FALSE;
03077        }
03078        dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
03079        DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
03080        dateobj->time->y = y;
03081        dateobj->time->m = m;
03082        dateobj->time->d = d;
03083        timelib_update_ts(dateobj->time, NULL);
03084 
03085        RETURN_ZVAL(object, 1, 0);
03086 }
03087 /* }}} */
03088 
03089 /* {{{ proto DateTime date_isodate_set(DateTime object, long year, long week[, long day])
03090    Sets the ISO date.
03091 */
03092 PHP_FUNCTION(date_isodate_set)
03093 {
03094        zval         *object;
03095        php_date_obj *dateobj;
03096        long          y, w, d = 1;
03097 
03098        if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_date, &y, &w, &d) == FAILURE) {
03099               RETURN_FALSE;
03100        }
03101        dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
03102        DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
03103        dateobj->time->y = y;
03104        dateobj->time->m = 1;
03105        dateobj->time->d = 1;
03106        memset(&dateobj->time->relative, 0, sizeof(dateobj->time->relative));
03107        dateobj->time->relative.d = timelib_daynr_from_weeknr(y, w, d);
03108        dateobj->time->have_relative = 1;
03109        
03110        timelib_update_ts(dateobj->time, NULL);
03111 
03112        RETURN_ZVAL(object, 1, 0);
03113 }
03114 /* }}} */
03115 
03116 /* {{{ proto DateTime date_timestamp_set(DateTime object, long unixTimestamp)
03117    Sets the date and time based on an Unix timestamp.
03118 */
03119 PHP_FUNCTION(date_timestamp_set)
03120 {
03121        zval         *object;
03122        php_date_obj *dateobj;
03123        long          timestamp;
03124 
03125        if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", &object, date_ce_date, &timestamp) == FAILURE) {
03126               RETURN_FALSE;
03127        }
03128        dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
03129        DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
03130        timelib_unixtime2local(dateobj->time, (timelib_sll)timestamp);
03131        timelib_update_ts(dateobj->time, NULL);
03132 
03133        RETURN_ZVAL(object, 1, 0);
03134 }
03135 /* }}} */
03136 
03137 /* {{{ proto long date_timestamp_get(DateTime object)
03138    Gets the Unix timestamp.
03139 */
03140 PHP_FUNCTION(date_timestamp_get)
03141 {
03142        zval         *object;
03143        php_date_obj *dateobj;
03144        long          timestamp;
03145        int           error;
03146 
03147        if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_date) == FAILURE) {
03148               RETURN_FALSE;
03149        }
03150        dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
03151        DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
03152        timelib_update_ts(dateobj->time, NULL);
03153 
03154        timestamp = timelib_date_to_int(dateobj->time, &error);
03155        if (error) {
03156               RETURN_FALSE;
03157        } else {
03158               RETVAL_LONG(timestamp);
03159        }
03160 }
03161 /* }}} */
03162 
03163 /* {{{ proto DateInterval date_diff(DateTime object [, bool absolute])
03164    Returns the difference between two DateTime objects.
03165 */
03166 PHP_FUNCTION(date_diff)
03167 {
03168        zval         *object1, *object2;
03169        php_date_obj *dateobj1, *dateobj2;
03170        php_interval_obj *interval;
03171        long          absolute = 0;
03172 
03173        if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO|l", &object1, date_ce_date, &object2, date_ce_date, &absolute) == FAILURE) {
03174               RETURN_FALSE;
03175        }
03176        dateobj1 = (php_date_obj *) zend_object_store_get_object(object1 TSRMLS_CC);
03177        dateobj2 = (php_date_obj *) zend_object_store_get_object(object2 TSRMLS_CC);
03178        DATE_CHECK_INITIALIZED(dateobj1->time, DateTime);
03179        DATE_CHECK_INITIALIZED(dateobj2->time, DateTime);
03180        timelib_update_ts(dateobj1->time, NULL);
03181        timelib_update_ts(dateobj2->time, NULL);
03182 
03183        php_date_instantiate(date_ce_interval, return_value TSRMLS_CC);
03184        interval = zend_object_store_get_object(return_value TSRMLS_CC);
03185        interval->diff = timelib_diff(dateobj1->time, dateobj2->time);
03186        if (absolute) {
03187               interval->diff->invert = 0;
03188        }
03189        interval->initialized = 1;
03190 }
03191 /* }}} */
03192 
03193 static int timezone_initialize(timelib_tzinfo **tzi, /*const*/ char *tz TSRMLS_DC)
03194 {
03195        char *tzid;
03196        
03197        *tzi = NULL;
03198        
03199        if ((tzid = timelib_timezone_id_from_abbr(tz, -1, 0))) {
03200               *tzi = php_date_parse_tzfile(tzid, DATE_TIMEZONEDB TSRMLS_CC);
03201        } else {
03202               *tzi = php_date_parse_tzfile(tz, DATE_TIMEZONEDB TSRMLS_CC);
03203        }
03204        
03205        if (*tzi) {
03206               return SUCCESS;
03207        } else {
03208               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or bad timezone (%s)", tz);
03209               return FAILURE;
03210        }
03211 }
03212 
03213 /* {{{ proto DateTimeZone timezone_open(string timezone)
03214    Returns new DateTimeZone object
03215 */
03216 PHP_FUNCTION(timezone_open)
03217 {
03218        char *tz;
03219        int   tz_len;
03220        timelib_tzinfo *tzi = NULL;
03221        php_timezone_obj *tzobj;
03222 
03223        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &tz, &tz_len) == FAILURE) {
03224               RETURN_FALSE;
03225        }
03226        if (SUCCESS != timezone_initialize(&tzi, tz TSRMLS_CC)) {
03227               RETURN_FALSE;
03228        }
03229        tzobj = zend_object_store_get_object(php_date_instantiate(date_ce_timezone, return_value TSRMLS_CC) TSRMLS_CC);
03230        tzobj->type = TIMELIB_ZONETYPE_ID;
03231        tzobj->tzi.tz = tzi;
03232        tzobj->initialized = 1;
03233 }
03234 /* }}} */
03235 
03236 /* {{{ proto DateTimeZone::__construct(string timezone)
03237    Creates new DateTimeZone object.
03238 */
03239 PHP_METHOD(DateTimeZone, __construct)
03240 {
03241        char *tz;
03242        int tz_len;
03243        timelib_tzinfo *tzi = NULL;
03244        php_timezone_obj *tzobj;
03245        zend_error_handling error_handling;
03246        
03247        zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
03248        if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &tz, &tz_len)) {
03249               if (SUCCESS == timezone_initialize(&tzi, tz TSRMLS_CC)) {
03250                      tzobj = zend_object_store_get_object(getThis() TSRMLS_CC);
03251                      tzobj->type = TIMELIB_ZONETYPE_ID;
03252                      tzobj->tzi.tz = tzi;
03253                      tzobj->initialized = 1;
03254               } else {
03255                      ZVAL_NULL(getThis());
03256               }
03257        }
03258        zend_restore_error_handling(&error_handling TSRMLS_CC);
03259 }
03260 /* }}} */
03261 
03262 /* {{{ proto string timezone_name_get(DateTimeZone object)
03263    Returns the name of the timezone.
03264 */
03265 PHP_FUNCTION(timezone_name_get)
03266 {
03267        zval             *object;
03268        php_timezone_obj *tzobj;
03269 
03270        if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_timezone) == FAILURE) {
03271               RETURN_FALSE;
03272        }
03273        tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
03274        DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
03275 
03276        switch (tzobj->type) {
03277               case TIMELIB_ZONETYPE_ID:
03278                      RETURN_STRING(tzobj->tzi.tz->name, 1);
03279                      break;
03280               case TIMELIB_ZONETYPE_OFFSET: {
03281                      char *tmpstr = emalloc(sizeof("UTC+05:00"));
03282                      timelib_sll utc_offset = tzobj->tzi.utc_offset;
03283 
03284                      snprintf(tmpstr, sizeof("+05:00"), "%c%02d:%02d",
03285                             utc_offset > 0 ? '-' : '+',
03286                             abs(utc_offset / 60),
03287                             abs((utc_offset % 60)));
03288 
03289                      RETURN_STRING(tmpstr, 0);
03290                      }
03291                      break;
03292               case TIMELIB_ZONETYPE_ABBR:
03293                      RETURN_STRING(tzobj->tzi.z.abbr, 1);
03294                      break;
03295        }
03296 }
03297 /* }}} */
03298 
03299 /* {{{ proto string timezone_name_from_abbr(string abbr[, long gmtOffset[, long isdst]])
03300    Returns the timezone name from abbrevation
03301 */
03302 PHP_FUNCTION(timezone_name_from_abbr)
03303 {
03304        char    *abbr;
03305        char    *tzid;
03306        int      abbr_len;
03307        long     gmtoffset = -1;
03308        long     isdst = -1;
03309 
03310        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ll", &abbr, &abbr_len, &gmtoffset, &isdst) == FAILURE) {
03311               RETURN_FALSE;
03312        }
03313        tzid = timelib_timezone_id_from_abbr(abbr, gmtoffset, isdst);
03314 
03315        if (tzid) {
03316               RETURN_STRING(tzid, 1);
03317        } else {
03318               RETURN_FALSE;
03319        }
03320 }
03321 /* }}} */
03322 
03323 /* {{{ proto long timezone_offset_get(DateTimeZone object, DateTime object)
03324    Returns the timezone offset.
03325 */
03326 PHP_FUNCTION(timezone_offset_get)
03327 {
03328        zval                *object, *dateobject;
03329        php_timezone_obj    *tzobj;
03330        php_date_obj        *dateobj;
03331        timelib_time_offset *offset;
03332 
03333        if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_timezone, &dateobject, date_ce_date) == FAILURE) {
03334               RETURN_FALSE;
03335        }
03336        tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
03337        DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
03338        dateobj = (php_date_obj *) zend_object_store_get_object(dateobject TSRMLS_CC);
03339        DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
03340 
03341        switch (tzobj->type) {
03342               case TIMELIB_ZONETYPE_ID:
03343                      offset = timelib_get_time_zone_info(dateobj->time->sse, tzobj->tzi.tz);
03344                      RETVAL_LONG(offset->offset);
03345                      timelib_time_offset_dtor(offset);
03346                      break;
03347               case TIMELIB_ZONETYPE_OFFSET:
03348                      RETURN_LONG(tzobj->tzi.utc_offset * -60);
03349                      break;
03350               case TIMELIB_ZONETYPE_ABBR:
03351                      RETURN_LONG((tzobj->tzi.z.utc_offset - (tzobj->tzi.z.dst*60)) * -60);
03352                      break;
03353        }
03354 }
03355 /* }}} */
03356 
03357 /* {{{ proto array timezone_transitions_get(DateTimeZone object [, long timestamp_begin [, long timestamp_end ]])
03358    Returns numerically indexed array containing associative array for all transitions in the specified range for the timezone.
03359 */
03360 PHP_FUNCTION(timezone_transitions_get)
03361 {
03362        zval                *object, *element;
03363        php_timezone_obj    *tzobj;
03364        unsigned int         i, begin = 0, found;
03365        long                 timestamp_begin = LONG_MIN, timestamp_end = LONG_MAX;
03366 
03367        if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|ll", &object, date_ce_timezone, &timestamp_begin, &timestamp_end) == FAILURE) {
03368               RETURN_FALSE;
03369        }
03370        tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
03371        DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
03372        if (tzobj->type != TIMELIB_ZONETYPE_ID) {
03373               RETURN_FALSE;
03374        }
03375 
03376 #define add_nominal() \
03377               MAKE_STD_ZVAL(element); \
03378               array_init(element); \
03379               add_assoc_long(element, "ts",     timestamp_begin); \
03380               add_assoc_string(element, "time", php_format_date(DATE_FORMAT_ISO8601, 13, timestamp_begin, 0 TSRMLS_CC), 0); \
03381               add_assoc_long(element, "offset", tzobj->tzi.tz->type[0].offset); \
03382               add_assoc_bool(element, "isdst",  tzobj->tzi.tz->type[0].isdst); \
03383               add_assoc_string(element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[0].abbr_idx], 1); \
03384               add_next_index_zval(return_value, element);
03385 
03386 #define add(i,ts) \
03387               MAKE_STD_ZVAL(element); \
03388               array_init(element); \
03389               add_assoc_long(element, "ts",     ts); \
03390               add_assoc_string(element, "time", php_format_date(DATE_FORMAT_ISO8601, 13, ts, 0 TSRMLS_CC), 0); \
03391               add_assoc_long(element, "offset", tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].offset); \
03392               add_assoc_bool(element, "isdst",  tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].isdst); \
03393               add_assoc_string(element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].abbr_idx], 1); \
03394               add_next_index_zval(return_value, element);
03395 
03396 #define add_last() add(tzobj->tzi.tz->timecnt - 1, timestamp_begin)
03397 
03398        array_init(return_value);
03399 
03400        if (timestamp_begin == LONG_MIN) {
03401               add_nominal();
03402               begin = 0;
03403               found = 1;
03404        } else {
03405               begin = 0;
03406               found = 0;
03407               if (tzobj->tzi.tz->timecnt > 0) {
03408                      do {
03409                             if (tzobj->tzi.tz->trans[begin] > timestamp_begin) {
03410                                    if (begin > 0) {
03411                                           add(begin - 1, timestamp_begin);
03412                                    } else {
03413                                           add_nominal();
03414                                    }
03415                                    found = 1;
03416                                    break;
03417                             }
03418                             begin++;
03419                      } while (begin < tzobj->tzi.tz->timecnt);
03420               }
03421        }
03422 
03423        if (!found) {
03424               if (tzobj->tzi.tz->timecnt > 0) {
03425                      add_last();
03426               } else {
03427                      add_nominal();
03428               }
03429        } else {
03430               for (i = begin; i < tzobj->tzi.tz->timecnt; ++i) {
03431                      if (tzobj->tzi.tz->trans[i] < timestamp_end) {
03432                             add(i, tzobj->tzi.tz->trans[i]);
03433                      }
03434               }
03435        }
03436 }
03437 /* }}} */
03438 
03439 /* {{{ proto array timezone_location_get()
03440    Returns location information for a timezone, including country code, latitude/longitude and comments
03441 */
03442 PHP_FUNCTION(timezone_location_get)
03443 {
03444        zval                *object;
03445        php_timezone_obj    *tzobj;
03446 
03447        if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_timezone) == FAILURE) {
03448               RETURN_FALSE;
03449        }
03450        tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
03451        DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
03452        if (tzobj->type != TIMELIB_ZONETYPE_ID) {
03453               RETURN_FALSE;
03454        }
03455 
03456        array_init(return_value);
03457        add_assoc_string(return_value, "country_code", tzobj->tzi.tz->location.country_code, 1);
03458        add_assoc_double(return_value, "latitude", tzobj->tzi.tz->location.latitude);
03459        add_assoc_double(return_value, "longitude", tzobj->tzi.tz->location.longitude);
03460        add_assoc_string(return_value, "comments", tzobj->tzi.tz->location.comments, 1);
03461 }
03462 /* }}} */
03463 
03464 static int date_interval_initialize(timelib_rel_time **rt, /*const*/ char *format, int format_length TSRMLS_DC)
03465 {
03466        timelib_time     *b = NULL, *e = NULL;
03467        timelib_rel_time *p = NULL;
03468        int               r = 0;
03469        int               retval = 0;
03470        struct timelib_error_container *errors;
03471 
03472        timelib_strtointerval(format, format_length, &b, &e, &p, &r, &errors);
03473        
03474        if (errors->error_count > 0) {
03475               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or bad format (%s)", format);
03476               retval = FAILURE;
03477        } else {
03478               if(p) {
03479                      *rt = p;
03480                      retval = SUCCESS;
03481               } else {
03482                      if(b && e) {
03483                             timelib_update_ts(b, NULL);
03484                             timelib_update_ts(e, NULL);
03485                             *rt = timelib_diff(b, e);
03486                             retval = SUCCESS;
03487                      } else {
03488                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse interval (%s)", format);
03489                             retval = FAILURE;
03490                      }
03491               }
03492        }
03493        timelib_error_container_dtor(errors);
03494        return retval;
03495 }
03496 
03497 /* {{{ date_interval_read_property */
03498 zval *date_interval_read_property(zval *object, zval *member, int type TSRMLS_DC)
03499 {
03500        php_interval_obj *obj;
03501        zval *retval;
03502        zval tmp_member;
03503        timelib_sll value = -1;
03504 
03505        if (member->type != IS_STRING) {
03506               tmp_member = *member;
03507               zval_copy_ctor(&tmp_member);
03508               convert_to_string(&tmp_member);
03509               member = &tmp_member;
03510        }
03511 
03512        obj = (php_interval_obj *)zend_objects_get_address(object TSRMLS_CC);
03513 
03514 #define GET_VALUE_FROM_STRUCT(n,m)            \
03515        if (strcmp(Z_STRVAL_P(member), m) == 0) { \
03516               value = obj->diff->n;                 \
03517               break;                                                    \
03518        }
03519        do {
03520               GET_VALUE_FROM_STRUCT(y, "y");
03521               GET_VALUE_FROM_STRUCT(m, "m");
03522               GET_VALUE_FROM_STRUCT(d, "d");
03523               GET_VALUE_FROM_STRUCT(h, "h");
03524               GET_VALUE_FROM_STRUCT(i, "i");
03525               GET_VALUE_FROM_STRUCT(s, "s");
03526               GET_VALUE_FROM_STRUCT(invert, "invert");
03527               GET_VALUE_FROM_STRUCT(days, "days");
03528               /* didn't find any */
03529               retval = (zend_get_std_object_handlers())->read_property(object, member, type TSRMLS_CC);
03530 
03531               if (member == &tmp_member) {
03532                      zval_dtor(member);
03533               }
03534 
03535               return retval;
03536        } while(0);
03537 
03538        ALLOC_INIT_ZVAL(retval);
03539        Z_SET_REFCOUNT_P(retval, 0);
03540 
03541        ZVAL_LONG(retval, value);
03542 
03543        if (member == &tmp_member) {
03544               zval_dtor(member);
03545        }
03546 
03547        return retval;
03548 }
03549 /* }}} */
03550 
03551 /* {{{ date_interval_write_property */
03552 void date_interval_write_property(zval *object, zval *member, zval *value TSRMLS_DC)
03553 {
03554        php_interval_obj *obj;
03555        zval tmp_member, tmp_value;
03556 
03557        if (member->type != IS_STRING) {
03558               tmp_member = *member;
03559               zval_copy_ctor(&tmp_member);
03560               convert_to_string(&tmp_member);
03561               member = &tmp_member;
03562        }
03563        obj = (php_interval_obj *)zend_objects_get_address(object TSRMLS_CC);
03564 
03565 #define SET_VALUE_FROM_STRUCT(n,m)            \
03566        if (strcmp(Z_STRVAL_P(member), m) == 0) { \
03567               if (value->type != IS_LONG) {         \
03568                      tmp_value = *value;               \
03569                      zval_copy_ctor(&tmp_value);       \
03570                      convert_to_long(&tmp_value);      \
03571                      value = &tmp_value;               \
03572               }                                     \
03573               obj->diff->n = Z_LVAL_P(value);       \
03574               if (value == &tmp_value) {            \
03575                      zval_dtor(value);                 \
03576               }                                     \
03577               break;                                                    \
03578        }
03579 
03580        do {
03581               SET_VALUE_FROM_STRUCT(y, "y");
03582               SET_VALUE_FROM_STRUCT(m, "m");
03583               SET_VALUE_FROM_STRUCT(d, "d");
03584               SET_VALUE_FROM_STRUCT(h, "h");
03585               SET_VALUE_FROM_STRUCT(i, "i");
03586               SET_VALUE_FROM_STRUCT(s, "s");
03587               SET_VALUE_FROM_STRUCT(invert, "invert");
03588               /* didn't find any */
03589               (zend_get_std_object_handlers())->write_property(object, member, value TSRMLS_CC);
03590        } while(0);
03591 
03592        if (member == &tmp_member) {
03593               zval_dtor(member);
03594        }
03595 }
03596 /* }}} */
03597 
03598 
03599 /* {{{ proto DateInterval::__construct([string interval_spec])
03600    Creates new DateInterval object.
03601 */
03602 PHP_METHOD(DateInterval, __construct)
03603 {
03604        char *interval_string = NULL;
03605        int   interval_string_length;
03606        php_interval_obj *diobj;
03607        timelib_rel_time *reltime;
03608        zend_error_handling error_handling;
03609        
03610        zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
03611        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &interval_string, &interval_string_length) == SUCCESS) {
03612               if (date_interval_initialize(&reltime, interval_string, interval_string_length TSRMLS_CC) == SUCCESS) {
03613                      diobj = zend_object_store_get_object(getThis() TSRMLS_CC);
03614                      diobj->diff = reltime;
03615                      diobj->initialized = 1;
03616               } else {
03617                      ZVAL_NULL(getThis());
03618               }
03619        }
03620        zend_restore_error_handling(&error_handling TSRMLS_CC);
03621 }
03622 /* }}} */
03623 
03624 static long php_date_long_from_hash_element(HashTable *myht, char *element, size_t size)
03625 {
03626        zval            **z_arg = NULL;
03627 
03628        if (zend_hash_find(myht, element, size + 1, (void**) &z_arg) == SUCCESS) {
03629               convert_to_long(*z_arg);
03630               return Z_LVAL_PP(z_arg);
03631        } else {
03632               return -1;
03633        }
03634 }
03635 
03636 static int php_date_interval_initialize_from_hash(zval **return_value, php_interval_obj **intobj, HashTable *myht TSRMLS_DC)
03637 {
03638        (*intobj)->diff = timelib_rel_time_ctor();
03639 
03640        (*intobj)->diff->y = php_date_long_from_hash_element(myht, "y", 1);
03641        (*intobj)->diff->m = php_date_long_from_hash_element(myht, "m", 1);
03642        (*intobj)->diff->d = php_date_long_from_hash_element(myht, "d", 1);
03643        (*intobj)->diff->h = php_date_long_from_hash_element(myht, "h", 1);
03644        (*intobj)->diff->i = php_date_long_from_hash_element(myht, "i", 1);
03645        (*intobj)->diff->s = php_date_long_from_hash_element(myht, "s", 1);
03646        (*intobj)->diff->invert = php_date_long_from_hash_element(myht, "invert", 6);
03647        (*intobj)->diff->days = php_date_long_from_hash_element(myht, "days", 4);
03648        (*intobj)->initialized = 1;
03649 
03650        return 0;
03651 }
03652 
03653 /* {{{ proto DateInterval::__set_state()
03654 */
03655 PHP_METHOD(DateInterval, __set_state)
03656 {
03657        php_interval_obj *intobj;
03658        zval             *array;
03659        HashTable        *myht;
03660 
03661        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
03662               RETURN_FALSE;
03663        }
03664 
03665        myht = HASH_OF(array);
03666 
03667        php_date_instantiate(date_ce_interval, return_value TSRMLS_CC);
03668        intobj = (php_interval_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
03669        php_date_interval_initialize_from_hash(&return_value, &intobj, myht TSRMLS_CC);
03670 }
03671 /* }}} */
03672 
03673 /* {{{ proto DateInterval::__wakeup()
03674 */
03675 PHP_METHOD(DateInterval, __wakeup)
03676 {
03677        zval             *object = getThis();
03678        php_interval_obj *intobj;
03679        HashTable        *myht;
03680 
03681        intobj = (php_interval_obj *) zend_object_store_get_object(object TSRMLS_CC);
03682 
03683        myht = Z_OBJPROP_P(object);
03684 
03685        php_date_interval_initialize_from_hash(&return_value, &intobj, myht TSRMLS_CC);
03686 }
03687 /* }}} */
03688 /* {{{ proto DateInterval date_interval_create_from_date_string(string time)
03689    Uses the normal date parsers and sets up a DateInterval from the relative parts of the parsed string
03690 */
03691 PHP_FUNCTION(date_interval_create_from_date_string)
03692 {
03693        char           *time_str = NULL;
03694        int             time_str_len = 0;
03695        timelib_time   *time;
03696        timelib_error_container *err = NULL;
03697        php_interval_obj *diobj;
03698 
03699        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &time_str, &time_str_len) == FAILURE) {
03700               RETURN_FALSE;
03701        }
03702 
03703        php_date_instantiate(date_ce_interval, return_value TSRMLS_CC);
03704 
03705        time = timelib_strtotime(time_str, time_str_len, &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
03706        diobj = (php_interval_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
03707        diobj->diff = timelib_rel_time_clone(&time->relative);
03708        diobj->initialized = 1;
03709        timelib_time_dtor(time);
03710        timelib_error_container_dtor(err);
03711 }
03712 /* }}} */
03713 
03714 /* {{{ date_interval_format -  */
03715 static char *date_interval_format(char *format, int format_len, timelib_rel_time *t)
03716 {
03717        smart_str            string = {0};
03718        int                  i, length, have_format_spec = 0;
03719        char                 buffer[33];
03720 
03721        if (!format_len) {
03722               return estrdup("");
03723        }
03724 
03725        for (i = 0; i < format_len; i++) {
03726               if (have_format_spec) {
03727                      switch (format[i]) {
03728                             case 'Y': length = slprintf(buffer, 32, "%02d", (int) t->y); break;
03729                             case 'y': length = slprintf(buffer, 32, "%d", (int) t->y); break;
03730 
03731                             case 'M': length = slprintf(buffer, 32, "%02d", (int) t->m); break;
03732                             case 'm': length = slprintf(buffer, 32, "%d", (int) t->m); break;
03733 
03734                             case 'D': length = slprintf(buffer, 32, "%02d", (int) t->d); break;
03735                             case 'd': length = slprintf(buffer, 32, "%d", (int) t->d); break;
03736 
03737                             case 'H': length = slprintf(buffer, 32, "%02d", (int) t->h); break;
03738                             case 'h': length = slprintf(buffer, 32, "%d", (int) t->h); break;
03739 
03740                             case 'I': length = slprintf(buffer, 32, "%02d", (int) t->i); break;
03741                             case 'i': length = slprintf(buffer, 32, "%d", (int) t->i); break;
03742 
03743                             case 'S': length = slprintf(buffer, 32, "%02ld", (long) t->s); break;
03744                             case 's': length = slprintf(buffer, 32, "%ld", (long) t->s); break;
03745 
03746                             case 'a': {
03747                                    if ((int) t->days != -99999) {
03748                                           length = slprintf(buffer, 32, "%d", (int) t->days);
03749                                    } else {
03750                                           length = slprintf(buffer, 32, "(unknown)");
03751                                    }
03752                             } break;
03753                             case 'r': length = slprintf(buffer, 32, "%s", t->invert ? "-" : ""); break;
03754                             case 'R': length = slprintf(buffer, 32, "%c", t->invert ? '-' : '+'); break;
03755 
03756                             case '%': length = slprintf(buffer, 32, "%%"); break;
03757                             default: buffer[0] = '%'; buffer[1] = format[i]; buffer[2] = '\0'; length = 2; break;
03758                      }
03759                      smart_str_appendl(&string, buffer, length);
03760                      have_format_spec = 0;
03761               } else {
03762                      if (format[i] == '%') {
03763                             have_format_spec = 1;
03764                      } else {
03765                             smart_str_appendc(&string, format[i]);
03766                      }
03767               }
03768        }
03769 
03770        smart_str_0(&string);
03771 
03772        return string.c;
03773 }
03774 /* }}} */
03775 
03776 /* {{{ proto string date_interval_format(DateInterval object, string format)
03777    Formats the interval.
03778 */
03779 PHP_FUNCTION(date_interval_format)
03780 {
03781        zval             *object;
03782        php_interval_obj *diobj;
03783        char             *format;
03784        int               format_len;
03785 
03786        if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_interval, &format, &format_len) == FAILURE) {
03787               RETURN_FALSE;
03788        }
03789        diobj = (php_interval_obj *) zend_object_store_get_object(object TSRMLS_CC);
03790        DATE_CHECK_INITIALIZED(diobj->initialized, DateInterval);
03791 
03792        RETURN_STRING(date_interval_format(format, format_len, diobj->diff), 0);
03793 }
03794 /* }}} */
03795 
03796 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)
03797 {
03798        timelib_time     *b = NULL, *e = NULL;
03799        timelib_rel_time *p = NULL;
03800        int               r = 0;
03801        int               retval = 0;
03802        struct timelib_error_container *errors;
03803 
03804        timelib_strtointerval(format, format_length, &b, &e, &p, &r, &errors);
03805        
03806        if (errors->error_count > 0) {
03807               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or bad format (%s)", format);
03808               retval = FAILURE;
03809        } else {
03810               *st = b;
03811               *et = e;
03812               *d  = p;
03813               *recurrences = r;
03814               retval = SUCCESS;
03815        }
03816        timelib_error_container_dtor(errors);
03817        return retval;
03818 }
03819 
03820 /* {{{ proto DatePeriod::__construct(DateTime $start, DateInterval $interval, int recurrences|DateTime $end)
03821    Creates new DatePeriod object.
03822 */
03823 PHP_METHOD(DatePeriod, __construct)
03824 {
03825        php_period_obj   *dpobj;
03826        php_date_obj     *dateobj;
03827        php_interval_obj *intobj;
03828        zval *start, *end = NULL, *interval;
03829        long  recurrences = 0, options = 0;
03830        char *isostr = NULL;
03831        int   isostr_len = 0;
03832        timelib_time *clone;
03833        zend_error_handling error_handling;
03834        
03835        zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
03836        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) {
03837               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) {
03838                      if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &isostr, &isostr_len, &options) == FAILURE) {
03839                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "This constructor accepts either (DateTime, DateInterval, int) OR (DateTime, DateInterval, DateTime) OR (string) as arguments.");
03840                             zend_restore_error_handling(&error_handling TSRMLS_CC);
03841                             return;
03842                      }
03843               }
03844        }
03845 
03846        dpobj = zend_object_store_get_object(getThis() TSRMLS_CC);
03847        dpobj->current = NULL;
03848 
03849        if (isostr) {
03850               date_period_initialize(&(dpobj->start), &(dpobj->end), &(dpobj->interval), &recurrences, isostr, isostr_len TSRMLS_CC);
03851               if (dpobj->start == NULL) {
03852                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "The ISO interval '%s' did not contain a start date.", isostr);
03853               }
03854               if (dpobj->interval == NULL) {
03855                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "The ISO interval '%s' did not contain an interval.", isostr);
03856               }
03857               if (dpobj->end == NULL && recurrences == 0) {
03858                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "The ISO interval '%s' did not contain an end date or a recurrence count.", isostr);
03859               }
03860 
03861               if (dpobj->start) {
03862                      timelib_update_ts(dpobj->start, NULL);
03863               }
03864               if (dpobj->end) {
03865                      timelib_update_ts(dpobj->end, NULL);
03866               }
03867        } else {
03868               /* init */
03869               intobj  = (php_interval_obj *) zend_object_store_get_object(interval TSRMLS_CC);
03870 
03871               /* start date */
03872               dateobj = (php_date_obj *) zend_object_store_get_object(start TSRMLS_CC);
03873               clone = timelib_time_ctor();
03874               memcpy(clone, dateobj->time, sizeof(timelib_time));
03875               if (dateobj->time->tz_abbr) {
03876                      clone->tz_abbr = strdup(dateobj->time->tz_abbr);
03877               }
03878               if (dateobj->time->tz_info) {
03879                      clone->tz_info = dateobj->time->tz_info;
03880               }
03881               dpobj->start = clone;
03882 
03883               /* interval */
03884               dpobj->interval = timelib_rel_time_clone(intobj->diff);
03885 
03886               /* end date */
03887               if (end) {
03888                      dateobj = (php_date_obj *) zend_object_store_get_object(end TSRMLS_CC);
03889                      clone = timelib_time_clone(dateobj->time);
03890                      dpobj->end = clone;
03891               }
03892        }
03893 
03894        /* options */
03895        dpobj->include_start_date = !(options & PHP_DATE_PERIOD_EXCLUDE_START_DATE);
03896 
03897        /* recurrrences */
03898        dpobj->recurrences = recurrences + dpobj->include_start_date;
03899 
03900        dpobj->initialized = 1;
03901 
03902        zend_restore_error_handling(&error_handling TSRMLS_CC);
03903 }
03904 /* }}} */
03905 
03906 static int check_id_allowed(char *id, long what)
03907 {
03908        if (what & PHP_DATE_TIMEZONE_GROUP_AFRICA     && strncasecmp(id, "Africa/",      7) == 0) return 1;
03909        if (what & PHP_DATE_TIMEZONE_GROUP_AMERICA    && strncasecmp(id, "America/",     8) == 0) return 1;
03910        if (what & PHP_DATE_TIMEZONE_GROUP_ANTARCTICA && strncasecmp(id, "Antarctica/", 11) == 0) return 1;
03911        if (what & PHP_DATE_TIMEZONE_GROUP_ARCTIC     && strncasecmp(id, "Arctic/",      7) == 0) return 1;
03912        if (what & PHP_DATE_TIMEZONE_GROUP_ASIA       && strncasecmp(id, "Asia/",        5) == 0) return 1;
03913        if (what & PHP_DATE_TIMEZONE_GROUP_ATLANTIC   && strncasecmp(id, "Atlantic/",    9) == 0) return 1;
03914        if (what & PHP_DATE_TIMEZONE_GROUP_AUSTRALIA  && strncasecmp(id, "Australia/",  10) == 0) return 1;
03915        if (what & PHP_DATE_TIMEZONE_GROUP_EUROPE     && strncasecmp(id, "Europe/",      7) == 0) return 1;
03916        if (what & PHP_DATE_TIMEZONE_GROUP_INDIAN     && strncasecmp(id, "Indian/",      7) == 0) return 1;
03917        if (what & PHP_DATE_TIMEZONE_GROUP_PACIFIC    && strncasecmp(id, "Pacific/",     8) == 0) return 1;
03918        if (what & PHP_DATE_TIMEZONE_GROUP_UTC        && strncasecmp(id, "UTC",          3) == 0) return 1;
03919        return 0;
03920 }
03921 
03922 /* {{{ proto array timezone_identifiers_list([long what[, string country]])
03923    Returns numerically index array with all timezone identifiers.
03924 */
03925 PHP_FUNCTION(timezone_identifiers_list)
03926 {
03927        const timelib_tzdb             *tzdb;
03928        const timelib_tzdb_index_entry *table;
03929        int                             i, item_count;
03930        long                            what = PHP_DATE_TIMEZONE_GROUP_ALL;
03931        char                           *option = NULL;
03932        int                             option_len = 0;
03933 
03934        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ls", &what, &option, &option_len) == FAILURE) {
03935               RETURN_FALSE;
03936        }
03937 
03938        /* Extra validation */
03939        if (what == PHP_DATE_TIMEZONE_PER_COUNTRY && option_len != 2) {
03940               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "A two-letter ISO 3166-1 compatible country code is expected");
03941               RETURN_FALSE;
03942        }
03943 
03944        tzdb = DATE_TIMEZONEDB;
03945        item_count = tzdb->index_size;
03946        table = tzdb->index;
03947        
03948        array_init(return_value);
03949 
03950        for (i = 0; i < item_count; ++i) {
03951               if (what == PHP_DATE_TIMEZONE_PER_COUNTRY) {
03952                      if (tzdb->data[table[i].pos + 5] == option[0] && tzdb->data[table[i].pos + 6] == option[1]) {
03953                             add_next_index_string(return_value, table[i].id, 1);
03954                      }
03955               } else if (what == PHP_DATE_TIMEZONE_GROUP_ALL_W_BC || (check_id_allowed(table[i].id, what) && (tzdb->data[table[i].pos + 4] == '\1'))) {
03956                      add_next_index_string(return_value, table[i].id, 1);
03957               }
03958        };
03959 }
03960 /* }}} */
03961 
03962 /* {{{ proto array timezone_version_get()
03963    Returns the Olson database version number.
03964 */
03965 PHP_FUNCTION(timezone_version_get)
03966 {
03967        const timelib_tzdb *tzdb;
03968 
03969        tzdb = DATE_TIMEZONEDB;
03970        RETURN_STRING(tzdb->version, 1);
03971 }
03972 /* }}} */
03973 
03974 /* {{{ proto array timezone_abbreviations_list()
03975    Returns associative array containing dst, offset and the timezone name
03976 */
03977 PHP_FUNCTION(timezone_abbreviations_list)
03978 {
03979        const timelib_tz_lookup_table *table, *entry;
03980        zval                          *element, **abbr_array_pp, *abbr_array;
03981        
03982        table = timelib_timezone_abbreviations_list();
03983        array_init(return_value);
03984        entry = table;
03985 
03986        do {
03987               MAKE_STD_ZVAL(element);
03988               array_init(element);
03989               add_assoc_bool(element, "dst", entry->type);
03990               add_assoc_long(element, "offset", entry->gmtoffset);
03991               if (entry->full_tz_name) {
03992                      add_assoc_string(element, "timezone_id", entry->full_tz_name, 1);
03993               } else {
03994                      add_assoc_null(element, "timezone_id");
03995               }
03996 
03997               if (zend_hash_find(HASH_OF(return_value), entry->name, strlen(entry->name) + 1, (void **) &abbr_array_pp) == FAILURE) {
03998                      MAKE_STD_ZVAL(abbr_array);
03999                      array_init(abbr_array);
04000                      add_assoc_zval(return_value, entry->name, abbr_array);
04001               } else {
04002                      abbr_array = *abbr_array_pp;
04003               }
04004               add_next_index_zval(abbr_array, element);
04005               entry++;
04006        } while (entry->name);
04007 }
04008 /* }}} */
04009 
04010 /* {{{ proto bool date_default_timezone_set(string timezone_identifier)
04011    Sets the default timezone used by all date/time functions in a script */
04012 PHP_FUNCTION(date_default_timezone_set)
04013 {
04014        char *zone;
04015        int   zone_len;
04016 
04017        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &zone, &zone_len) == FAILURE) {
04018               RETURN_FALSE;
04019        }
04020        if (!timelib_timezone_id_is_valid(zone, DATE_TIMEZONEDB)) {
04021               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Timezone ID '%s' is invalid", zone);
04022               RETURN_FALSE;
04023        }
04024        if (DATEG(timezone)) {
04025               efree(DATEG(timezone));
04026               DATEG(timezone) = NULL;
04027        }
04028        DATEG(timezone) = estrndup(zone, zone_len);
04029        RETURN_TRUE;
04030 }
04031 /* }}} */
04032 
04033 /* {{{ proto string date_default_timezone_get()
04034    Gets the default timezone used by all date/time functions in a script */
04035 PHP_FUNCTION(date_default_timezone_get)
04036 {
04037        timelib_tzinfo *default_tz;
04038 
04039        default_tz = get_timezone_info(TSRMLS_C);
04040        RETVAL_STRING(default_tz->name, 1);
04041 }
04042 /* }}} */
04043 
04044 /* {{{ php_do_date_sunrise_sunset
04045  *  Common for date_sunrise() and date_sunset() functions
04046  */
04047 static void php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAMETERS, int calc_sunset)
04048 {
04049        double latitude = 0.0, longitude = 0.0, zenith = 0.0, gmt_offset = 0, altitude;
04050        double h_rise, h_set, N;
04051        timelib_sll rise, set, transit;
04052        long time, retformat = 0;
04053        int             rs;
04054        timelib_time   *t;
04055        timelib_tzinfo *tzi;
04056        char           *retstr;
04057        
04058        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|ldddd", &time, &retformat, &latitude, &longitude, &zenith, &gmt_offset) == FAILURE) {
04059               RETURN_FALSE;
04060        }
04061        
04062        switch (ZEND_NUM_ARGS()) {
04063               case 1:
04064                      retformat = SUNFUNCS_RET_STRING;
04065               case 2:
04066                      latitude = INI_FLT("date.default_latitude");
04067               case 3:
04068                      longitude = INI_FLT("date.default_longitude");
04069               case 4:
04070                      if (calc_sunset) {
04071                             zenith = INI_FLT("date.sunset_zenith");
04072                      } else {
04073                             zenith = INI_FLT("date.sunrise_zenith");
04074                      }
04075               case 5:
04076               case 6:
04077                      break;
04078               default:
04079                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid format");
04080                      RETURN_FALSE;
04081                      break;
04082        }
04083        if (retformat != SUNFUNCS_RET_TIMESTAMP &&
04084               retformat != SUNFUNCS_RET_STRING &&
04085               retformat != SUNFUNCS_RET_DOUBLE)
04086        {
04087               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");
04088               RETURN_FALSE;
04089        }
04090        altitude = 90 - zenith;
04091 
04092        /* Initialize time struct */
04093        t = timelib_time_ctor();
04094        tzi = get_timezone_info(TSRMLS_C);
04095        t->tz_info = tzi;
04096        t->zone_type = TIMELIB_ZONETYPE_ID;
04097 
04098        if (ZEND_NUM_ARGS() <= 5) {
04099               gmt_offset = timelib_get_current_offset(t) / 3600;
04100        }
04101 
04102        timelib_unixtime2local(t, time);
04103        rs = timelib_astro_rise_set_altitude(t, longitude, latitude, altitude, 1, &h_rise, &h_set, &rise, &set, &transit);
04104        timelib_time_dtor(t);
04105        
04106        if (rs != 0) {
04107               RETURN_FALSE;
04108        }
04109 
04110        if (retformat == SUNFUNCS_RET_TIMESTAMP) {
04111               RETURN_LONG(calc_sunset ? set : rise);
04112        }
04113        N = (calc_sunset ? h_set : h_rise) + gmt_offset;
04114 
04115        if (N > 24 || N < 0) {
04116               N -= floor(N / 24) * 24;
04117        }
04118 
04119        switch (retformat) {
04120               case SUNFUNCS_RET_STRING:
04121                      spprintf(&retstr, 0, "%02d:%02d", (int) N, (int) (60 * (N - (int) N)));
04122                      RETURN_STRINGL(retstr, 5, 0);
04123                      break;
04124               case SUNFUNCS_RET_DOUBLE:
04125                      RETURN_DOUBLE(N);
04126                      break;
04127        }
04128 }
04129 /* }}} */
04130 
04131 /* {{{ proto mixed date_sunrise(mixed time [, int format [, float latitude [, float longitude [, float zenith [, float gmt_offset]]]]])
04132    Returns time of sunrise for a given day and location */
04133 PHP_FUNCTION(date_sunrise)
04134 {
04135        php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
04136 }
04137 /* }}} */
04138 
04139 /* {{{ proto mixed date_sunset(mixed time [, int format [, float latitude [, float longitude [, float zenith [, float gmt_offset]]]]])
04140    Returns time of sunset for a given day and location */
04141 PHP_FUNCTION(date_sunset)
04142 {
04143        php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
04144 }
04145 /* }}} */
04146 
04147 /* {{{ proto array date_sun_info(long time, float latitude, float longitude)
04148    Returns an array with information about sun set/rise and twilight begin/end */
04149 PHP_FUNCTION(date_sun_info)
04150 {
04151        long            time;
04152        double          latitude, longitude;
04153        timelib_time   *t, *t2;
04154        timelib_tzinfo *tzi;
04155        int             rs;
04156        timelib_sll     rise, set, transit;
04157        int             dummy;
04158        double          ddummy;
04159        
04160        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ldd", &time, &latitude, &longitude) == FAILURE) {
04161               RETURN_FALSE;
04162        }
04163        /* Initialize time struct */
04164        t = timelib_time_ctor();
04165        tzi = get_timezone_info(TSRMLS_C);
04166        t->tz_info = tzi;
04167        t->zone_type = TIMELIB_ZONETYPE_ID;
04168        timelib_unixtime2local(t, time);
04169 
04170        /* Setup */
04171        t2 = timelib_time_ctor();
04172        array_init(return_value);
04173        
04174        /* Get sun up/down and transit */
04175        rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -35.0/60, 1, &ddummy, &ddummy, &rise, &set, &transit);
04176        switch (rs) {
04177               case -1: /* always below */
04178                      add_assoc_bool(return_value, "sunrise", 0);
04179                      add_assoc_bool(return_value, "sunset", 0);
04180                      break;
04181               case 1: /* always above */
04182                      add_assoc_bool(return_value, "sunrise", 1);
04183                      add_assoc_bool(return_value, "sunset", 1);
04184                      break;
04185               default:
04186                      t2->sse = rise;
04187                      add_assoc_long(return_value, "sunrise", timelib_date_to_int(t2, &dummy));
04188                      t2->sse = set;
04189                      add_assoc_long(return_value, "sunset", timelib_date_to_int(t2, &dummy));
04190        }
04191        t2->sse = transit;
04192        add_assoc_long(return_value, "transit", timelib_date_to_int(t2, &dummy));
04193 
04194        /* Get civil twilight */
04195        rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -6.0, 0, &ddummy, &ddummy, &rise, &set, &transit);
04196        switch (rs) {
04197               case -1: /* always below */
04198                      add_assoc_bool(return_value, "civil_twilight_begin", 0);
04199                      add_assoc_bool(return_value, "civil_twilight_end", 0);
04200                      break;
04201               case 1: /* always above */
04202                      add_assoc_bool(return_value, "civil_twilight_begin", 1);
04203                      add_assoc_bool(return_value, "civil_twilight_end", 1);
04204                      break;
04205               default:
04206                      t2->sse = rise;
04207                      add_assoc_long(return_value, "civil_twilight_begin", timelib_date_to_int(t2, &dummy));
04208                      t2->sse = set;
04209                      add_assoc_long(return_value, "civil_twilight_end", timelib_date_to_int(t2, &dummy));
04210        }
04211 
04212        /* Get nautical twilight */
04213        rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -12.0, 0, &ddummy, &ddummy, &rise, &set, &transit);
04214        switch (rs) {
04215               case -1: /* always below */
04216                      add_assoc_bool(return_value, "nautical_twilight_begin", 0);
04217                      add_assoc_bool(return_value, "nautical_twilight_end", 0);
04218                      break;
04219               case 1: /* always above */
04220                      add_assoc_bool(return_value, "nautical_twilight_begin", 1);
04221                      add_assoc_bool(return_value, "nautical_twilight_end", 1);
04222                      break;
04223               default:
04224                      t2->sse = rise;
04225                      add_assoc_long(return_value, "nautical_twilight_begin", timelib_date_to_int(t2, &dummy));
04226                      t2->sse = set;
04227                      add_assoc_long(return_value, "nautical_twilight_end", timelib_date_to_int(t2, &dummy));
04228        }
04229 
04230        /* Get astronomical twilight */
04231        rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -18.0, 0, &ddummy, &ddummy, &rise, &set, &transit);
04232        switch (rs) {
04233               case -1: /* always below */
04234                      add_assoc_bool(return_value, "astronomical_twilight_begin", 0);
04235                      add_assoc_bool(return_value, "astronomical_twilight_end", 0);
04236                      break;
04237               case 1: /* always above */
04238                      add_assoc_bool(return_value, "astronomical_twilight_begin", 1);
04239                      add_assoc_bool(return_value, "astronomical_twilight_end", 1);
04240                      break;
04241               default:
04242                      t2->sse = rise;
04243                      add_assoc_long(return_value, "astronomical_twilight_begin", timelib_date_to_int(t2, &dummy));
04244                      t2->sse = set;
04245                      add_assoc_long(return_value, "astronomical_twilight_end", timelib_date_to_int(t2, &dummy));
04246        }
04247        timelib_time_dtor(t);
04248        timelib_time_dtor(t2);
04249 }
04250 /* }}} */
04251 /*
04252  * Local variables:
04253  * tab-width: 4
04254  * c-basic-offset: 4
04255  * End:
04256  * vim600: fdm=marker
04257  * vim: noet sw=4 ts=4
04258  */