diff options
Diffstat (limited to 'ext/date/php_date.c')
-rw-r--r-- | ext/date/php_date.c | 681 |
1 files changed, 590 insertions, 91 deletions
diff --git a/ext/date/php_date.c b/ext/date/php_date.c index f091fed182..f0c9525e56 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -399,7 +399,9 @@ const zend_function_entry date_functions[] = { /* Advanced Interface */ PHP_FE(date_create, arginfo_date_create) + PHP_FE(date_create_immutable, arginfo_date_create) PHP_FE(date_create_from_format, arginfo_date_create_from_format) + PHP_FE(date_create_immutable_from_format, arginfo_date_create_from_format) PHP_FE(date_parse, arginfo_date_parse) PHP_FE(date_parse_from_format, arginfo_date_parse_from_format) PHP_FE(date_get_last_errors, arginfo_date_get_last_errors) @@ -442,6 +444,16 @@ const zend_function_entry date_functions[] = { PHP_FE_END }; +static const zend_function_entry date_funcs_interface[] = { + PHP_ABSTRACT_ME(DateTimeInterface, format, arginfo_date_method_format) + PHP_ABSTRACT_ME(DateTimeInterface, getTimezone, arginfo_date_method_timezone_get) + PHP_ABSTRACT_ME(DateTimeInterface, getOffset, arginfo_date_method_offset_get) + PHP_ABSTRACT_ME(DateTimeInterface, getTimestamp, arginfo_date_method_timestamp_get) + PHP_ABSTRACT_ME(DateTimeInterface, diff, arginfo_date_method_diff) + PHP_ABSTRACT_ME(DateTimeInterface, __wakeup, NULL) + PHP_FE_END +}; + const zend_function_entry date_funcs_date[] = { PHP_ME(DateTime, __construct, arginfo_date_create, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC) PHP_ME(DateTime, __wakeup, NULL, ZEND_ACC_PUBLIC) @@ -464,8 +476,32 @@ const zend_function_entry date_funcs_date[] = { PHP_FE_END }; +const zend_function_entry date_funcs_immutable[] = { + PHP_ME(DateTimeImmutable, __construct, arginfo_date_create, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC) + PHP_ME(DateTime, __wakeup, NULL, ZEND_ACC_PUBLIC) + PHP_ME(DateTimeImmutable, __set_state, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + PHP_ME_MAPPING(createFromFormat, date_create_from_format, arginfo_date_create_from_format, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + PHP_ME_MAPPING(getLastErrors, date_get_last_errors, arginfo_date_get_last_errors, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + PHP_ME_MAPPING(format, date_format, arginfo_date_method_format, 0) + PHP_ME_MAPPING(getTimezone, date_timezone_get, arginfo_date_method_timezone_get, 0) + PHP_ME_MAPPING(getOffset, date_offset_get, arginfo_date_method_offset_get, 0) + PHP_ME_MAPPING(getTimestamp, date_timestamp_get, arginfo_date_method_timestamp_get, 0) + PHP_ME_MAPPING(diff, date_diff, arginfo_date_method_diff, 0) + PHP_ME(DateTimeImmutable, modify, arginfo_date_method_modify, 0) + PHP_ME(DateTimeImmutable, add, arginfo_date_method_add, 0) + PHP_ME(DateTimeImmutable, sub, arginfo_date_method_sub, 0) + PHP_ME(DateTimeImmutable, setTimezone, arginfo_date_method_timezone_set, 0) + PHP_ME(DateTimeImmutable, setTime, arginfo_date_method_time_set, 0) + PHP_ME(DateTimeImmutable, setDate, arginfo_date_method_date_set, 0) + PHP_ME(DateTimeImmutable, setISODate, arginfo_date_method_isodate_set, 0) + PHP_ME(DateTimeImmutable, setTimestamp, arginfo_date_method_timestamp_set, 0) + PHP_FE_END +}; + const zend_function_entry date_funcs_timezone[] = { PHP_ME(DateTimeZone, __construct, arginfo_timezone_open, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC) + PHP_ME(DateTimeZone, __wakeup, NULL, ZEND_ACC_PUBLIC) + PHP_ME(DateTimeZone, __set_state, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME_MAPPING(getName, timezone_name_get, arginfo_timezone_method_name_get, 0) PHP_ME_MAPPING(getOffset, timezone_offset_get, arginfo_timezone_method_offset_get, 0) PHP_ME_MAPPING(getTransitions, timezone_transitions_get, arginfo_timezone_method_transitions_get, 0) @@ -524,6 +560,7 @@ PHP_INI_END() /* }}} */ zend_class_entry *date_ce_date, *date_ce_timezone, *date_ce_interval, *date_ce_period; +zend_class_entry *date_ce_immutable, *date_ce_interface; PHPAPI zend_class_entry *php_date_get_date_ce(void) @@ -531,12 +568,18 @@ PHPAPI zend_class_entry *php_date_get_date_ce(void) return date_ce_date; } +PHPAPI zend_class_entry *php_date_get_immutable_ce(void) +{ + return date_ce_immutable; +} + PHPAPI zend_class_entry *php_date_get_timezone_ce(void) { return date_ce_timezone; } static zend_object_handlers date_object_handlers_date; +static zend_object_handlers date_object_handlers_immutable; static zend_object_handlers date_object_handlers_timezone; static zend_object_handlers date_object_handlers_interval; static zend_object_handlers date_object_handlers_period; @@ -587,6 +630,8 @@ static HashTable *date_object_get_gc_interval(zval *object, zval ***table, int * static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC); static HashTable *date_object_get_gc_period(zval *object, zval ***table, int *n TSRMLS_DC); static HashTable *date_object_get_properties_period(zval *object TSRMLS_DC); +static HashTable *date_object_get_properties_timezone(zval *object TSRMLS_DC); +static HashTable *date_object_get_gc_timezone(zval *object, zval ***table, int *n TSRMLS_DC); zval *date_interval_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC); void date_interval_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC); @@ -763,7 +808,6 @@ PHP_RSHUTDOWN_FUNCTION(date) #define SUNFUNCS_RET_STRING 1 #define SUNFUNCS_RET_DOUBLE 2 - /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(date) { @@ -1376,7 +1420,6 @@ PHPAPI signed long php_parse_date(char *string, signed long *now) } /* }}} */ - /* {{{ proto int strtotime(string time [, int now ]) Convert string representation of date and time to a timestamp */ PHP_FUNCTION(strtotime) @@ -1437,7 +1480,6 @@ PHP_FUNCTION(strtotime) } /* }}} */ - /* {{{ php_mktime - (gm)mktime helper */ PHPAPI void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gmt) { @@ -1546,7 +1588,6 @@ PHP_FUNCTION(gmmktime) } /* }}} */ - /* {{{ proto bool checkdate(int month, int day, int year) Returns true(1) if it is a valid date in gregorian calendar */ PHP_FUNCTION(checkdate) @@ -1573,7 +1614,7 @@ PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gmt) long timestamp = 0; struct tm ta; int max_reallocs = 5; - size_t buf_len = 64, real_len; + size_t buf_len = 256, real_len; timelib_time *ts; timelib_tzinfo *tzi; timelib_time_offset *offset = NULL; @@ -1626,6 +1667,9 @@ PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gmt) #endif } + /* VS2012 crt has a bug where strftime crash with %z and %Z format when the + initial buffer is too small. See + http://connect.microsoft.com/VisualStudio/feedback/details/759720/vs2012-strftime-crash-with-z-formatting-code */ buf = (char *) emalloc(buf_len); while ((real_len=strftime(buf, buf_len, format, &ta))==buf_len || real_len==0) { buf_len *= 2; @@ -1634,6 +1678,13 @@ PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gmt) break; } } +#if defined(PHP_WIN32) && _MSC_VER >= 1700 + /* VS2012 strftime() returns number of characters, not bytes. + See VC++11 bug id 766205. */ + if (real_len > 0) { + real_len = strlen(buf); + } +#endif timelib_time_dtor(ts); if (!gmt) { @@ -1846,7 +1897,7 @@ static void date_period_it_current_data(zend_object_iterator *iter, zval ***data /* Create new object */ MAKE_STD_ZVAL(iterator->current); - php_date_instantiate(date_ce_date, iterator->current TSRMLS_CC); + php_date_instantiate(object->start_ce, iterator->current TSRMLS_CC); newdateobj = (php_date_obj *) zend_object_store_get_object(iterator->current TSRMLS_CC); newdateobj->time = timelib_time_ctor(); *newdateobj->time = *it_time; @@ -1863,11 +1914,10 @@ static void date_period_it_current_data(zend_object_iterator *iter, zval ***data /* {{{ date_period_it_current_key */ -static int date_period_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) +static void date_period_it_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC) { - date_period_it *iterator = (date_period_it *)iter; - *int_key = iterator->current_index; - return HASH_KEY_IS_LONG; + date_period_it *iterator = (date_period_it *)iter; + ZVAL_LONG(key, iterator->current_index); } /* }}} */ @@ -1932,7 +1982,10 @@ zend_object_iterator *date_object_period_get_iterator(zend_class_entry *ce, zval static void date_register_classes(TSRMLS_D) { - zend_class_entry ce_date, ce_timezone, ce_interval, ce_period; + zend_class_entry ce_date, ce_immutable, ce_timezone, ce_interval, ce_period, ce_interface; + + INIT_CLASS_ENTRY(ce_interface, "DateTimeInterface", date_funcs_interface); + date_ce_interface = zend_register_internal_interface(&ce_interface TSRMLS_CC); INIT_CLASS_ENTRY(ce_date, "DateTime", date_funcs_date); ce_date.create_object = date_object_new_date; @@ -1942,6 +1995,7 @@ static void date_register_classes(TSRMLS_D) date_object_handlers_date.compare_objects = date_object_compare_date; date_object_handlers_date.get_properties = date_object_get_properties; date_object_handlers_date.get_gc = date_object_get_gc; + zend_class_implements(date_ce_date TSRMLS_CC, 1, date_ce_interface); #define REGISTER_DATE_CLASS_CONST_STRING(const_name, value) \ zend_declare_class_constant_stringl(date_ce_date, const_name, sizeof(const_name)-1, value, sizeof(value)-1 TSRMLS_CC); @@ -1958,12 +2012,22 @@ static void date_register_classes(TSRMLS_D) REGISTER_DATE_CLASS_CONST_STRING("RSS", DATE_FORMAT_RFC1123); REGISTER_DATE_CLASS_CONST_STRING("W3C", DATE_FORMAT_RFC3339); + INIT_CLASS_ENTRY(ce_immutable, "DateTimeImmutable", date_funcs_immutable); + ce_immutable.create_object = date_object_new_date; + date_ce_immutable = zend_register_internal_class_ex(&ce_immutable, NULL, NULL TSRMLS_CC); + memcpy(&date_object_handlers_immutable, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + date_object_handlers_immutable.clone_obj = date_object_clone_date; + date_object_handlers_immutable.compare_objects = date_object_compare_date; + date_object_handlers_immutable.get_properties = date_object_get_properties; + zend_class_implements(date_ce_immutable TSRMLS_CC, 1, date_ce_interface); INIT_CLASS_ENTRY(ce_timezone, "DateTimeZone", date_funcs_timezone); ce_timezone.create_object = date_object_new_timezone; date_ce_timezone = zend_register_internal_class_ex(&ce_timezone, NULL, NULL TSRMLS_CC); memcpy(&date_object_handlers_timezone, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); date_object_handlers_timezone.clone_obj = date_object_clone_timezone; + date_object_handlers_timezone.get_properties = date_object_get_properties_timezone; + date_object_handlers_timezone.get_gc = date_object_get_gc_timezone; #define REGISTER_TIMEZONE_CLASS_CONST_STRING(const_name, value) \ zend_declare_class_constant_long(date_ce_timezone, const_name, sizeof(const_name)-1, value TSRMLS_CC); @@ -2063,6 +2127,19 @@ static zend_object_value date_object_clone_date(zval *this_ptr TSRMLS_DC) return new_ov; } +static zval* date_clone_immutable(zval *object TSRMLS_DC) +{ + zval *new_object; + + ALLOC_ZVAL(new_object); + Z_OBJVAL_P(new_object) = date_object_clone_date(object TSRMLS_CC); + Z_SET_REFCOUNT_P(new_object, 1); + Z_SET_ISREF_P(new_object); + Z_TYPE_P(new_object) = IS_OBJECT; + + return new_object; +} + static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC) { if (Z_TYPE_P(d1) == IS_OBJECT && Z_TYPE_P(d2) == IS_OBJECT && @@ -2095,6 +2172,14 @@ static HashTable *date_object_get_gc(zval *object, zval ***table, int *n TSRMLS_ return zend_std_get_properties(object TSRMLS_CC); } +static HashTable *date_object_get_gc_timezone(zval *object, zval ***table, int *n TSRMLS_DC) +{ + + *table = NULL; + *n = 0; + return zend_std_get_properties(object TSRMLS_CC); +} + static HashTable *date_object_get_properties(zval *object TSRMLS_DC) { HashTable *props; @@ -2203,6 +2288,50 @@ static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC) return new_ov; } +static HashTable *date_object_get_properties_timezone(zval *object TSRMLS_DC) +{ + HashTable *props; + zval *zv; + php_timezone_obj *tzobj; + + + tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC); + + props = zend_std_get_properties(object TSRMLS_CC); + + if (!tzobj->initialized) { + return props; + } + + MAKE_STD_ZVAL(zv); + ZVAL_LONG(zv, tzobj->type); + zend_hash_update(props, "timezone_type", 14, &zv, sizeof(zval), NULL); + + MAKE_STD_ZVAL(zv); + switch (tzobj->type) { + case TIMELIB_ZONETYPE_ID: + ZVAL_STRING(zv, tzobj->tzi.tz->name, 1); + break; + case TIMELIB_ZONETYPE_OFFSET: { + char *tmpstr = emalloc(sizeof("UTC+05:00")); + + snprintf(tmpstr, sizeof("+05:00"), "%c%02d:%02d", + tzobj->tzi.utc_offset > 0 ? '-' : '+', + abs(tzobj->tzi.utc_offset / 60), + abs((tzobj->tzi.utc_offset % 60))); + + ZVAL_STRING(zv, tmpstr, 0); + } + break; + case TIMELIB_ZONETYPE_ABBR: + ZVAL_STRING(zv, tzobj->tzi.z.abbr, 1); + break; + } + zend_hash_update(props, "timezone", 9, &zv, sizeof(zval), NULL); + + return props; +} + static inline zend_object_value date_object_new_interval_ex(zend_class_entry *class_type, php_interval_obj **ptr TSRMLS_DC) { php_interval_obj *intern; @@ -2506,6 +2635,26 @@ PHP_FUNCTION(date_create) } /* }}} */ +/* {{{ proto DateTime date_create_immutable([string time[, DateTimeZone object]]) + Returns new DateTime object +*/ +PHP_FUNCTION(date_create_immutable) +{ + zval *timezone_object = NULL; + char *time_str = NULL; + int time_str_len = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sO!", &time_str, &time_str_len, &timezone_object, date_ce_timezone) == FAILURE) { + RETURN_FALSE; + } + + php_date_instantiate(date_ce_immutable, return_value TSRMLS_CC); + if (!php_date_initialize(zend_object_store_get_object(return_value TSRMLS_CC), time_str, time_str_len, NULL, timezone_object, 0 TSRMLS_CC)) { + RETURN_FALSE; + } +} +/* }}} */ + /* {{{ proto DateTime date_create_from_format(string format, string time[, DateTimeZone object]) Returns new DateTime object formatted according to the specified format */ @@ -2526,6 +2675,26 @@ PHP_FUNCTION(date_create_from_format) } /* }}} */ +/* {{{ proto DateTime date_create_immutable_from_format(string format, string time[, DateTimeZone object]) + Returns new DateTime object formatted according to the specified format +*/ +PHP_FUNCTION(date_create_immutable_from_format) +{ + zval *timezone_object = NULL; + char *time_str = NULL, *format_str = NULL; + int time_str_len = 0, format_str_len = 0; + + 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) { + RETURN_FALSE; + } + + php_date_instantiate(date_ce_immutable, return_value TSRMLS_CC); + 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)) { + RETURN_FALSE; + } +} +/* }}} */ + /* {{{ proto DateTime::__construct([string time[, DateTimeZone object]]) Creates new DateTime object */ @@ -2544,6 +2713,24 @@ PHP_METHOD(DateTime, __construct) } /* }}} */ +/* {{{ proto DateTimeImmutable::__construct([string time[, DateTimeZone object]]) + Creates new DateTimeImmutable object +*/ +PHP_METHOD(DateTimeImmutable, __construct) +{ + zval *timezone_object = NULL; + char *time_str = NULL; + int time_str_len = 0; + zend_error_handling error_handling; + + zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC); + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sO!", &time_str, &time_str_len, &timezone_object, date_ce_timezone)) { + php_date_initialize(zend_object_store_get_object(getThis() TSRMLS_CC), time_str, time_str_len, NULL, timezone_object, 1 TSRMLS_CC); + } + zend_restore_error_handling(&error_handling TSRMLS_CC); +} +/* }}} */ + static int php_date_initialize_from_hash(zval **return_value, php_date_obj **dateobj, HashTable *myht TSRMLS_DC) { zval **z_date = NULL; @@ -2616,6 +2803,28 @@ PHP_METHOD(DateTime, __set_state) } /* }}} */ +/* {{{ proto DateTimeImmutable::__set_state() +*/ +PHP_METHOD(DateTimeImmutable, __set_state) +{ + php_date_obj *dateobj; + zval *array; + HashTable *myht; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) { + RETURN_FALSE; + } + + myht = HASH_OF(array); + + php_date_instantiate(date_ce_immutable, return_value TSRMLS_CC); + dateobj = (php_date_obj *) zend_object_store_get_object(return_value TSRMLS_CC); + if (!php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC)) { + php_error(E_ERROR, "Invalid serialization data for DateTimeImmutable object"); + } +} +/* }}} */ + /* {{{ proto DateTime::__wakeup() */ PHP_METHOD(DateTime, __wakeup) @@ -2784,7 +2993,7 @@ PHP_FUNCTION(date_parse_from_format) } /* }}} */ -/* {{{ proto string date_format(DateTime object, string format) +/* {{{ proto string date_format(DateTimeInterface object, string format) Returns date formatted according to given format */ PHP_FUNCTION(date_format) @@ -2794,7 +3003,7 @@ PHP_FUNCTION(date_format) char *format; int format_len; - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_date, &format, &format_len) == FAILURE) { + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_interface, &format, &format_len) == FAILURE) { RETURN_FALSE; } dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); @@ -2803,23 +3012,18 @@ PHP_FUNCTION(date_format) } /* }}} */ -/* {{{ proto DateTime date_modify(DateTime object, string modify) - Alters the timestamp. -*/ -PHP_FUNCTION(date_modify) +static int php_date_modify(zval *object, char *modify, int modify_len TSRMLS_DC) { - zval *object; php_date_obj *dateobj; - char *modify; - int modify_len; timelib_time *tmp_time; timelib_error_container *err = NULL; - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_date, &modify, &modify_len) == FAILURE) { - RETURN_FALSE; - } dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + + if (!(dateobj->time)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "The DateTime object has not been correctly initialized by its constructor"); + return 0; + } tmp_time = timelib_strtotime(modify, modify_len, &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper); @@ -2830,7 +3034,7 @@ PHP_FUNCTION(date_modify) php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse time string (%s) at position %d (%c): %s", modify, err->error_messages[0].position, err->error_messages[0].character, err->error_messages[0].message); timelib_time_dtor(tmp_time); - RETURN_FALSE; + return 0; } memcpy(&dateobj->time->relative, &tmp_time->relative, sizeof(struct timelib_rel_time)); @@ -2866,30 +3070,63 @@ PHP_FUNCTION(date_modify) timelib_update_ts(dateobj->time, NULL); timelib_update_from_sse(dateobj->time); dateobj->time->have_relative = 0; + + return 1; +} - RETURN_ZVAL(object, 1, 0); +/* {{{ proto DateTime date_modify(DateTime object, string modify) + Alters the timestamp. +*/ +PHP_FUNCTION(date_modify) +{ + zval *object; + char *modify; + int modify_len; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_date, &modify, &modify_len) == FAILURE) { + RETURN_FALSE; + } + + if (php_date_modify(object, modify, modify_len TSRMLS_CC)) { + RETURN_ZVAL(object, 1, 0); + } + + RETURN_FALSE; } /* }}} */ -/* {{{ proto DateTime date_add(DateTime object, DateInterval interval) - Adds an interval to the current date in object. +/* {{{ proto DateTimeImmutable::modify() */ -PHP_FUNCTION(date_add) +PHP_METHOD(DateTimeImmutable, modify) { - zval *object, *interval; - php_date_obj *dateobj; - php_interval_obj *intobj; - int bias = 1; + zval *object, *new_object; + char *modify; + int modify_len; - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) { + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_immutable, &modify, &modify_len) == FAILURE) { RETURN_FALSE; } + + new_object = date_clone_immutable(object TSRMLS_CC); + if (php_date_modify(new_object, modify, modify_len TSRMLS_CC)) { + RETURN_ZVAL(new_object, 0, 1); + } + + RETURN_FALSE; +} +/* }}} */ + +static void php_date_add(zval *object, zval *interval, zval *return_value TSRMLS_DC) +{ + php_date_obj *dateobj; + php_interval_obj *intobj; + int bias = 1; + dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); DATE_CHECK_INITIALIZED(dateobj->time, DateTime); intobj = (php_interval_obj *) zend_object_store_get_object(interval TSRMLS_CC); DATE_CHECK_INITIALIZED(intobj->initialized, DateInterval); - if (intobj->diff->have_weekday_relative || intobj->diff->have_special_relative) { memcpy(&dateobj->time->relative, intobj->diff, sizeof(struct timelib_rel_time)); } else { @@ -2910,24 +3147,48 @@ PHP_FUNCTION(date_add) timelib_update_ts(dateobj->time, NULL); timelib_update_from_sse(dateobj->time); dateobj->time->have_relative = 0; +} + +/* {{{ proto DateTime date_add(DateTime object, DateInterval interval) + Adds an interval to the current date in object. +*/ +PHP_FUNCTION(date_add) +{ + zval *object, *interval; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) { + RETURN_FALSE; + } + + php_date_add(object, interval, return_value TSRMLS_CC); RETURN_ZVAL(object, 1, 0); } /* }}} */ -/* {{{ proto DateTime date_sub(DateTime object, DateInterval interval) - Subtracts an interval to the current date in object. +/* {{{ proto DateTimeImmutable::add() */ -PHP_FUNCTION(date_sub) +PHP_METHOD(DateTimeImmutable, add) { - zval *object, *interval; - php_date_obj *dateobj; - php_interval_obj *intobj; - int bias = 1; + zval *object, *interval, *new_object; - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) { + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_immutable, &interval, date_ce_interval) == FAILURE) { RETURN_FALSE; } + + new_object = date_clone_immutable(object TSRMLS_CC); + php_date_add(new_object, interval, return_value TSRMLS_CC); + + RETURN_ZVAL(new_object, 0, 1); +} +/* }}} */ + +static void php_date_sub(zval *object, zval *interval, zval *return_value TSRMLS_DC) +{ + php_date_obj *dateobj; + php_interval_obj *intobj; + int bias = 1; + dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); DATE_CHECK_INITIALIZED(dateobj->time, DateTime); intobj = (php_interval_obj *) zend_object_store_get_object(interval TSRMLS_CC); @@ -2956,12 +3217,43 @@ PHP_FUNCTION(date_sub) timelib_update_from_sse(dateobj->time); dateobj->time->have_relative = 0; +} + +/* {{{ proto DateTime date_sub(DateTime object, DateInterval interval) + Subtracts an interval to the current date in object. +*/ +PHP_FUNCTION(date_sub) +{ + zval *object, *interval; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) { + RETURN_FALSE; + } + + php_date_sub(object, interval, return_value TSRMLS_CC); RETURN_ZVAL(object, 1, 0); } /* }}} */ -/* {{{ proto DateTimeZone date_timezone_get(DateTime object) +/* {{{ proto DateTimeImmutable::sub() +*/ +PHP_METHOD(DateTimeImmutable, sub) +{ + zval *object, *interval, *new_object; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_immutable, &interval, date_ce_interval) == FAILURE) { + RETURN_FALSE; + } + + new_object = date_clone_immutable(object TSRMLS_CC); + php_date_sub(new_object, interval, return_value TSRMLS_CC); + + RETURN_ZVAL(new_object, 0, 1); +} +/* }}} */ + +/* {{{ proto DateTimeZone date_timezone_get(DateTimeInterface object) Return new DateTimeZone object relative to give DateTime */ PHP_FUNCTION(date_timezone_get) @@ -2970,7 +3262,7 @@ PHP_FUNCTION(date_timezone_get) php_date_obj *dateobj; php_timezone_obj *tzobj; - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_date) == FAILURE) { + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_interface) == FAILURE) { RETURN_FALSE; } dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); @@ -2999,19 +3291,11 @@ PHP_FUNCTION(date_timezone_get) } /* }}} */ -/* {{{ proto DateTime date_timezone_set(DateTime object, DateTimeZone object) - Sets the timezone for the DateTime object. -*/ -PHP_FUNCTION(date_timezone_set) +static void php_date_timezone_set(zval *object, zval *timezone_object, zval *return_value TSRMLS_DC) { - zval *object; - zval *timezone_object; php_date_obj *dateobj; php_timezone_obj *tzobj; - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &timezone_object, date_ce_timezone) == FAILURE) { - RETURN_FALSE; - } dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); DATE_CHECK_INITIALIZED(dateobj->time, DateTime); tzobj = (php_timezone_obj *) zend_object_store_get_object(timezone_object TSRMLS_CC); @@ -3021,12 +3305,45 @@ PHP_FUNCTION(date_timezone_set) } timelib_set_timezone(dateobj->time, tzobj->tzi.tz); timelib_unixtime2local(dateobj->time, dateobj->time->sse); +} + +/* {{{ proto DateTime date_timezone_set(DateTime object, DateTimeZone object) + Sets the timezone for the DateTime object. +*/ +PHP_FUNCTION(date_timezone_set) +{ + zval *object; + zval *timezone_object; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &timezone_object, date_ce_timezone) == FAILURE) { + RETURN_FALSE; + } + + php_date_timezone_set(object, timezone_object, return_value TSRMLS_CC); RETURN_ZVAL(object, 1, 0); } /* }}} */ -/* {{{ proto long date_offset_get(DateTime object) +/* {{{ proto DateTimeImmutable::setTimezone() +*/ +PHP_METHOD(DateTimeImmutable, setTimezone) +{ + zval *object, *new_object; + zval *timezone_object; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_immutable, &timezone_object, date_ce_timezone) == FAILURE) { + RETURN_FALSE; + } + + new_object = date_clone_immutable(object TSRMLS_CC); + php_date_timezone_set(new_object, timezone_object, return_value TSRMLS_CC); + + RETURN_ZVAL(new_object, 0, 1); +} +/* }}} */ + +/* {{{ proto long date_offset_get(DateTimeInterface object) Returns the DST offset. */ PHP_FUNCTION(date_offset_get) @@ -3035,7 +3352,7 @@ PHP_FUNCTION(date_offset_get) php_date_obj *dateobj; timelib_time_offset *offset; - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_date) == FAILURE) { + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_interface) == FAILURE) { RETURN_FALSE; } dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); @@ -3061,64 +3378,106 @@ PHP_FUNCTION(date_offset_get) } /* }}} */ -/* {{{ proto DateTime date_time_set(DateTime object, long hour, long minute[, long second]) - Sets the time. -*/ -PHP_FUNCTION(date_time_set) +static void php_date_time_set(zval *object, long h, long i, long s, zval *return_value TSRMLS_DC) { - zval *object; php_date_obj *dateobj; - long h, i, s = 0; - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_date, &h, &i, &s) == FAILURE) { - RETURN_FALSE; - } dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); DATE_CHECK_INITIALIZED(dateobj->time, DateTime); dateobj->time->h = h; dateobj->time->i = i; dateobj->time->s = s; timelib_update_ts(dateobj->time, NULL); +} + +/* {{{ proto DateTime date_time_set(DateTime object, long hour, long minute[, long second]) + Sets the time. +*/ +PHP_FUNCTION(date_time_set) +{ + zval *object; + long h, i, s = 0; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_date, &h, &i, &s) == FAILURE) { + RETURN_FALSE; + } + + php_date_time_set(object, h, i, s, return_value TSRMLS_CC); RETURN_ZVAL(object, 1, 0); } /* }}} */ -/* {{{ proto DateTime date_date_set(DateTime object, long year, long month, long day) - Sets the date. +/* {{{ proto DateTimeImmutable::setTime() */ -PHP_FUNCTION(date_date_set) +PHP_METHOD(DateTimeImmutable, setTime) { - zval *object; - php_date_obj *dateobj; - long y, m, d; + zval *object, *new_object; + long h, i, s = 0; - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Olll", &object, date_ce_date, &y, &m, &d) == FAILURE) { + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_immutable, &h, &i, &s) == FAILURE) { RETURN_FALSE; } + + new_object = date_clone_immutable(object TSRMLS_CC); + php_date_time_set(new_object, h, i, s, return_value TSRMLS_CC); + + RETURN_ZVAL(new_object, 0, 1); +} +/* }}} */ + +static void php_date_date_set(zval *object, long y, long m, long d, zval *return_value TSRMLS_DC) +{ + php_date_obj *dateobj; + dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); DATE_CHECK_INITIALIZED(dateobj->time, DateTime); dateobj->time->y = y; dateobj->time->m = m; dateobj->time->d = d; timelib_update_ts(dateobj->time, NULL); +} + +/* {{{ proto DateTime date_date_set(DateTime object, long year, long month, long day) + Sets the date. +*/ +PHP_FUNCTION(date_date_set) +{ + zval *object; + long y, m, d; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Olll", &object, date_ce_date, &y, &m, &d) == FAILURE) { + RETURN_FALSE; + } + + php_date_date_set(object, y, m, d, return_value TSRMLS_CC); RETURN_ZVAL(object, 1, 0); } /* }}} */ -/* {{{ proto DateTime date_isodate_set(DateTime object, long year, long week[, long day]) - Sets the ISO date. +/* {{{ proto DateTimeImmutable::setDate() */ -PHP_FUNCTION(date_isodate_set) +PHP_METHOD(DateTimeImmutable, setDate) { - zval *object; - php_date_obj *dateobj; - long y, w, d = 1; + zval *object, *new_object; + long y, m, d; - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_date, &y, &w, &d) == FAILURE) { + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Olll", &object, date_ce_immutable, &y, &m, &d) == FAILURE) { RETURN_FALSE; } + + new_object = date_clone_immutable(object TSRMLS_CC); + php_date_date_set(new_object, y, m, d, return_value TSRMLS_CC); + + RETURN_ZVAL(new_object, 0, 1); +} +/* }}} */ + +static void php_date_isodate_set(zval *object, long y, long w, long d, zval *return_value TSRMLS_DC) +{ + php_date_obj *dateobj; + dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); DATE_CHECK_INITIALIZED(dateobj->time, DateTime); dateobj->time->y = y; @@ -3129,33 +3488,91 @@ PHP_FUNCTION(date_isodate_set) dateobj->time->have_relative = 1; timelib_update_ts(dateobj->time, NULL); +} + +/* {{{ proto DateTime date_isodate_set(DateTime object, long year, long week[, long day]) + Sets the ISO date. +*/ +PHP_FUNCTION(date_isodate_set) +{ + zval *object; + long y, w, d = 1; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_date, &y, &w, &d) == FAILURE) { + RETURN_FALSE; + } + + php_date_isodate_set(object, y, w, d, return_value TSRMLS_CC); RETURN_ZVAL(object, 1, 0); } /* }}} */ -/* {{{ proto DateTime date_timestamp_set(DateTime object, long unixTimestamp) - Sets the date and time based on an Unix timestamp. +/* {{{ proto DateTimeImmutable::setISODate() */ -PHP_FUNCTION(date_timestamp_set) +PHP_METHOD(DateTimeImmutable, setISODate) { - zval *object; - php_date_obj *dateobj; - long timestamp; + zval *object, *new_object; + long y, w, d = 1; - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", &object, date_ce_date, ×tamp) == FAILURE) { + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_immutable, &y, &w, &d) == FAILURE) { RETURN_FALSE; } + + new_object = date_clone_immutable(object TSRMLS_CC); + php_date_isodate_set(new_object, y, w, d, return_value TSRMLS_CC); + + RETURN_ZVAL(new_object, 0, 1); +} +/* }}} */ + +static void php_date_timestamp_set(zval *object, long timestamp, zval *return_value TSRMLS_DC) +{ + php_date_obj *dateobj; + dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); DATE_CHECK_INITIALIZED(dateobj->time, DateTime); timelib_unixtime2local(dateobj->time, (timelib_sll)timestamp); timelib_update_ts(dateobj->time, NULL); +} + +/* {{{ proto DateTime date_timestamp_set(DateTime object, long unixTimestamp) + Sets the date and time based on an Unix timestamp. +*/ +PHP_FUNCTION(date_timestamp_set) +{ + zval *object; + long timestamp; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", &object, date_ce_date, ×tamp) == FAILURE) { + RETURN_FALSE; + } + + php_date_timestamp_set(object, timestamp, return_value TSRMLS_CC); RETURN_ZVAL(object, 1, 0); } /* }}} */ -/* {{{ proto long date_timestamp_get(DateTime object) +/* {{{ proto DateTimeImmutable::setTimestamp() +*/ +PHP_METHOD(DateTimeImmutable, setTimestamp) +{ + zval *object, *new_object; + long timestamp; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", &object, date_ce_immutable, ×tamp) == FAILURE) { + RETURN_FALSE; + } + + new_object = date_clone_immutable(object TSRMLS_CC); + php_date_timestamp_set(new_object, timestamp, return_value TSRMLS_CC); + + RETURN_ZVAL(new_object, 0, 1); +} +/* }}} */ + +/* {{{ proto long date_timestamp_get(DateTimeInterface object) Gets the Unix timestamp. */ PHP_FUNCTION(date_timestamp_get) @@ -3165,7 +3582,7 @@ PHP_FUNCTION(date_timestamp_get) long timestamp; int error; - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_date) == FAILURE) { + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_interface) == FAILURE) { RETURN_FALSE; } dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); @@ -3280,6 +3697,85 @@ PHP_METHOD(DateTimeZone, __construct) } /* }}} */ +static int php_date_timezone_initialize_from_hash(zval **return_value, php_timezone_obj **tzobj, HashTable *myht TSRMLS_DC) +{ + zval **z_timezone = NULL; + zval **z_timezone_type = NULL; + timelib_tzinfo *tzi; + + if (zend_hash_find(myht, "timezone_type", 14, (void**) &z_timezone_type) == SUCCESS) { + if (zend_hash_find(myht, "timezone", 9, (void**) &z_timezone) == SUCCESS) { + convert_to_long(*z_timezone_type); + switch (Z_LVAL_PP(z_timezone_type)) { + case TIMELIB_ZONETYPE_OFFSET: { + char *offset, *offset_start; + + offset = emalloc(sizeof(char) * (Z_STRLEN_PP(z_timezone) + 1)); + memmove(offset, Z_STRVAL_PP(z_timezone), Z_STRLEN_PP(z_timezone)+1); + offset_start = offset; + + ++offset; + if(*offset_start == '+'){ + (*tzobj)->tzi.utc_offset = -1 * timelib_parse_tz_cor(&offset); + } else { + (*tzobj)->tzi.utc_offset = timelib_parse_tz_cor(&offset); + } + efree(offset_start); + (*tzobj)->type = TIMELIB_ZONETYPE_OFFSET; + (*tzobj)->initialized = 1; + return SUCCESS; + break; + } + case TIMELIB_ZONETYPE_ABBR: + case TIMELIB_ZONETYPE_ID: + if (SUCCESS == timezone_initialize(&tzi, Z_STRVAL_PP(z_timezone) TSRMLS_CC)) { + (*tzobj)->type = TIMELIB_ZONETYPE_ID; + (*tzobj)->tzi.tz = tzi; + (*tzobj)->initialized = 1; + return SUCCESS; + } + } + } + } + return FAILURE; +} + +/* {{{ proto DateTimeZone::__set_state() + * */ +PHP_METHOD(DateTimeZone, __set_state) +{ + php_timezone_obj *tzobj; + zval *array; + HashTable *myht; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) { + RETURN_FALSE; + } + + myht = HASH_OF(array); + + php_date_instantiate(date_ce_timezone, return_value TSRMLS_CC); + tzobj = (php_timezone_obj *) zend_object_store_get_object(return_value TSRMLS_CC); + php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto DateTimeZone::__wakeup() + * */ +PHP_METHOD(DateTimeZone, __wakeup) +{ + zval *object = getThis(); + php_timezone_obj *tzobj; + HashTable *myht; + + tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC); + + myht = Z_OBJPROP_P(object); + + php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht TSRMLS_CC); +} +/* }}} */ + /* {{{ proto string timezone_name_get(DateTimeZone object) Returns the name of the timezone. */ @@ -3891,10 +4387,10 @@ PHP_METHOD(DatePeriod, __construct) zend_error_handling error_handling; zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC); - if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "OOl|l", &start, date_ce_date, &interval, date_ce_interval, &recurrences, &options) == FAILURE) { - if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "OOO|l", &start, date_ce_date, &interval, date_ce_interval, &end, date_ce_date, &options) == FAILURE) { + 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) { + 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) { if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &isostr, &isostr_len, &options) == FAILURE) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "This constructor accepts either (DateTime, DateInterval, int) OR (DateTime, DateInterval, DateTime) OR (string) as arguments."); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "This constructor accepts either (DateTimeInterface, DateInterval, int) OR (DateTimeInterface, DateInterval, DateTime) OR (string) as arguments."); zend_restore_error_handling(&error_handling TSRMLS_CC); return; } @@ -3922,6 +4418,7 @@ PHP_METHOD(DatePeriod, __construct) if (dpobj->end) { timelib_update_ts(dpobj->end, NULL); } + dpobj->start_ce = date_ce_date; } else { /* init */ intobj = (php_interval_obj *) zend_object_store_get_object(interval TSRMLS_CC); @@ -3937,6 +4434,7 @@ PHP_METHOD(DatePeriod, __construct) clone->tz_info = dateobj->time->tz_info; } dpobj->start = clone; + dpobj->start_ce = Z_OBJCE_P(start); /* interval */ dpobj->interval = timelib_rel_time_clone(intobj->diff); @@ -4396,6 +4894,7 @@ static int php_date_period_initialize_from_hash(php_period_obj *period_obj, Hash php_date_obj *date_obj; date_obj = zend_object_store_get_object(*ht_entry TSRMLS_CC); period_obj->start = timelib_time_clone(date_obj->time); + period_obj->start_ce = Z_OBJCE_PP(ht_entry); } else if (Z_TYPE_PP(ht_entry) != IS_NULL) { return 0; } |