root/ext/date/php_date.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_date_llabs
  2. php_date_llabs
  3. php_date_llabs
  4. PHP_INI_BEGIN
  5. php_date_get_immutable_ce
  6. php_date_get_timezone_ce
  7. PHP_GINIT_FUNCTION
  8. _php_date_tzinfo_dtor
  9. PHP_RINIT_FUNCTION
  10. PHP_RSHUTDOWN_FUNCTION
  11. PHP_MINIT_FUNCTION
  12. PHP_MSHUTDOWN_FUNCTION
  13. PHP_MINFO_FUNCTION
  14. php_date_parse_tzfile
  15. php_date_parse_tzfile_wrapper
  16. PHP_INI_MH
  17. guess_timezone
  18. get_timezone_info
  19. english_suffix
  20. php_date_full_day_name
  21. php_date_short_day_name
  22. date_format
  23. php_date
  24. php_format_date
  25. php_idate
  26. PHP_FUNCTION
  27. PHP_FUNCTION
  28. PHP_FUNCTION
  29. php_date_set_tzdb
  30. php_parse_date
  31. PHP_FUNCTION
  32. php_mktime
  33. PHP_FUNCTION
  34. PHP_FUNCTION
  35. PHP_FUNCTION
  36. php_strftime
  37. PHP_FUNCTION
  38. PHP_FUNCTION
  39. PHP_FUNCTION
  40. PHP_FUNCTION
  41. PHP_FUNCTION
  42. date_period_it_invalidate_current
  43. date_period_it_dtor
  44. date_period_it_has_more
  45. date_period_it_current_data
  46. date_period_it_current_key
  47. date_period_it_move_forward
  48. date_period_it_rewind
  49. date_object_period_get_iterator
  50. implement_date_interface_handler
  51. date_register_classes
  52. date_object_new_date_ex
  53. date_object_new_date
  54. date_object_clone_date
  55. date_clone_immutable
  56. date_object_compare_date
  57. date_object_get_gc
  58. date_object_get_gc_timezone
  59. date_object_get_properties
  60. date_object_new_timezone_ex
  61. date_object_new_timezone
  62. date_object_clone_timezone
  63. date_object_get_properties_timezone
  64. date_object_new_interval_ex
  65. date_object_new_interval
  66. date_object_clone_interval
  67. date_object_get_gc_interval
  68. date_object_get_properties_interval
  69. date_object_new_period_ex
  70. date_object_new_period
  71. date_object_clone_period
  72. date_object_free_storage_date
  73. date_object_free_storage_timezone
  74. date_object_free_storage_interval
  75. date_object_free_storage_period
  76. php_date_instantiate
  77. update_errors_warnings
  78. php_date_initialize
  79. PHP_FUNCTION
  80. PHP_FUNCTION
  81. PHP_FUNCTION
  82. PHP_FUNCTION
  83. PHP_METHOD
  84. PHP_METHOD
  85. PHP_METHOD
  86. php_date_initialize_from_hash
  87. PHP_METHOD
  88. PHP_METHOD
  89. PHP_METHOD
  90. zval_from_error_container
  91. PHP_FUNCTION
  92. php_date_do_return_parsed_time
  93. PHP_FUNCTION
  94. PHP_FUNCTION
  95. PHP_FUNCTION
  96. php_date_modify
  97. PHP_FUNCTION
  98. PHP_METHOD
  99. php_date_add
  100. PHP_FUNCTION
  101. PHP_METHOD
  102. php_date_sub
  103. PHP_FUNCTION
  104. PHP_METHOD
  105. set_timezone_from_timelib_time
  106. PHP_FUNCTION
  107. php_date_timezone_set
  108. PHP_FUNCTION
  109. PHP_METHOD
  110. PHP_FUNCTION
  111. php_date_time_set
  112. PHP_FUNCTION
  113. PHP_METHOD
  114. php_date_date_set
  115. PHP_FUNCTION
  116. PHP_METHOD
  117. php_date_isodate_set
  118. PHP_FUNCTION
  119. PHP_METHOD
  120. php_date_timestamp_set
  121. PHP_FUNCTION
  122. PHP_METHOD
  123. PHP_FUNCTION
  124. PHP_FUNCTION
  125. timezone_initialize
  126. PHP_FUNCTION
  127. PHP_METHOD
  128. php_date_timezone_initialize_from_hash
  129. PHP_METHOD
  130. PHP_METHOD
  131. PHP_FUNCTION
  132. PHP_FUNCTION
  133. PHP_FUNCTION
  134. PHP_FUNCTION
  135. PHP_FUNCTION
  136. date_interval_initialize
  137. date_interval_read_property
  138. date_interval_write_property
  139. PHP_METHOD
  140. php_date_interval_initialize_from_hash
  141. PHP_METHOD
  142. PHP_METHOD
  143. PHP_FUNCTION
  144. date_interval_format
  145. PHP_FUNCTION
  146. date_period_initialize
  147. PHP_METHOD
  148. PHP_METHOD
  149. PHP_METHOD
  150. PHP_METHOD
  151. check_id_allowed
  152. PHP_FUNCTION
  153. PHP_FUNCTION
  154. PHP_FUNCTION
  155. PHP_FUNCTION
  156. PHP_FUNCTION
  157. php_do_date_sunrise_sunset
  158. PHP_FUNCTION
  159. PHP_FUNCTION
  160. PHP_FUNCTION
  161. date_object_get_gc_period
  162. date_object_get_properties_period
  163. php_date_period_initialize_from_hash
  164. PHP_METHOD
  165. PHP_METHOD
  166. date_period_read_property
  167. date_period_write_property

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

/* [<][>][^][v][top][bottom][index][help] */