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