diff options
Diffstat (limited to 'ext/date/php_date.c')
-rw-r--r-- | ext/date/php_date.c | 171 |
1 files changed, 90 insertions, 81 deletions
diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 35c018e324..dbcd7d8695 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -299,6 +299,10 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO(arginfo_date_method_timestamp_get, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_create_from_mutable, 0, 0, 1) + ZEND_ARG_INFO(0, DateTime) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_open, 0, 0, 1) ZEND_ARG_INFO(0, timezone) ZEND_END_ARG_INFO() @@ -495,6 +499,7 @@ const zend_function_entry date_funcs_immutable[] = { 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_ME(DateTimeImmutable, createFromMutable, arginfo_date_method_create_from_mutable, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_FE_END }; @@ -2267,7 +2272,7 @@ static zend_object *date_object_clone_timezone(zval *this_ptr TSRMLS_DC) /* {{{ case TIMELIB_ZONETYPE_ABBR: new_obj->tzi.z.utc_offset = old_obj->tzi.z.utc_offset; new_obj->tzi.z.dst = old_obj->tzi.z.dst; - new_obj->tzi.z.abbr = old_obj->tzi.z.abbr; + new_obj->tzi.z.abbr = strdup(old_obj->tzi.z.abbr); break; } @@ -2699,6 +2704,34 @@ PHP_METHOD(DateTimeImmutable, __construct) } /* }}} */ +/* {{{ proto DateTimeImmutable::createFromMutable(DateTimeZone object) + Creates new DateTimeImmutable object from an existing mutable DateTime object. +*/ +PHP_METHOD(DateTimeImmutable, createFromMutable) +{ + zval *datetime_object = NULL; + php_date_obj *new_obj = NULL; + php_date_obj *old_obj = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O!", &datetime_object, date_ce_date) == FAILURE) { + return; + } + + php_date_instantiate(date_ce_immutable, return_value TSRMLS_CC); + old_obj = Z_PHPDATE_P(datetime_object); + new_obj = Z_PHPDATE_P(return_value); + + new_obj->time = timelib_time_ctor(); + *new_obj->time = *old_obj->time; + if (old_obj->time->tz_abbr) { + new_obj->time->tz_abbr = strdup(old_obj->time->tz_abbr); + } + if (old_obj->time->tz_info) { + new_obj->time->tz_info = old_obj->time->tz_info; + } +} +/* }}} */ + static int php_date_initialize_from_hash(zval *return_value, php_date_obj **dateobj, HashTable *myht TSRMLS_DC) /* {{{ */ { zval *z_date; @@ -2735,6 +2768,10 @@ static int php_date_initialize_from_hash(zval *return_value, php_date_obj **date tzi = php_date_parse_tzfile(Z_STRVAL_P(z_timezone), DATE_TIMEZONEDB TSRMLS_CC); + if (tzi == NULL) { + return 0; + } + tzobj = Z_PHPTIMEZONE_P(php_date_instantiate(date_ce_timezone, &tmp_obj TSRMLS_CC)); tzobj->type = TIMELIB_ZONETYPE_ID; tzobj->tzi.tz = tzi; @@ -3188,6 +3225,26 @@ PHP_METHOD(DateTimeImmutable, sub) } /* }}} */ +static void set_timezone_from_timelib_time(php_timezone_obj *tzobj, timelib_time *t) +{ + tzobj->initialized = 1; + tzobj->type = t->zone_type; + switch (t->zone_type) { + case TIMELIB_ZONETYPE_ID: + tzobj->tzi.tz = t->tz_info; + break; + case TIMELIB_ZONETYPE_OFFSET: + tzobj->tzi.utc_offset = t->z; + break; + case TIMELIB_ZONETYPE_ABBR: + tzobj->tzi.z.utc_offset = t->z; + tzobj->tzi.z.dst = t->dst; + tzobj->tzi.z.abbr = strdup(t->tz_abbr); + break; + } +} + + /* {{{ proto DateTimeZone date_timezone_get(DateTimeInterface object) Return new DateTimeZone object relative to give DateTime */ @@ -3205,21 +3262,7 @@ PHP_FUNCTION(date_timezone_get) if (dateobj->time->is_localtime/* && dateobj->time->tz_info*/) { php_date_instantiate(date_ce_timezone, return_value TSRMLS_CC); tzobj = Z_PHPTIMEZONE_P(return_value); - tzobj->initialized = 1; - tzobj->type = dateobj->time->zone_type; - switch (dateobj->time->zone_type) { - case TIMELIB_ZONETYPE_ID: - tzobj->tzi.tz = dateobj->time->tz_info; - break; - case TIMELIB_ZONETYPE_OFFSET: - tzobj->tzi.utc_offset = dateobj->time->z; - break; - case TIMELIB_ZONETYPE_ABBR: - tzobj->tzi.z.utc_offset = dateobj->time->z; - tzobj->tzi.z.dst = dateobj->time->dst; - tzobj->tzi.z.abbr = strdup(dateobj->time->tz_abbr); - break; - } + set_timezone_from_timelib_time(tzobj, dateobj->time); } else { RETURN_FALSE; } @@ -3234,11 +3277,18 @@ static void php_date_timezone_set(zval *object, zval *timezone_object, zval *ret dateobj = Z_PHPDATE_P(object); DATE_CHECK_INITIALIZED(dateobj->time, DateTime); tzobj = Z_PHPTIMEZONE_P(timezone_object); - if (tzobj->type != TIMELIB_ZONETYPE_ID) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can only do this for zones with ID for now"); - return; + + switch (tzobj->type) { + case TIMELIB_ZONETYPE_OFFSET: + timelib_set_timezone_from_offset(dateobj->time, tzobj->tzi.utc_offset); + break; + case TIMELIB_ZONETYPE_ABBR: + timelib_set_timezone_from_abbr(dateobj->time, tzobj->tzi.z); + break; + case TIMELIB_ZONETYPE_ID: + timelib_set_timezone(dateobj->time, tzobj->tzi.tz); + break; } - timelib_set_timezone(dateobj->time, tzobj->tzi.tz); timelib_unixtime2local(dateobj->time, dateobj->time->sse); } /* }}} */ @@ -3563,23 +3613,21 @@ PHP_FUNCTION(date_diff) } /* }}} */ -static int timezone_initialize(timelib_tzinfo **tzi, /*const*/ char *tz TSRMLS_DC) /* {{{ */ +static int timezone_initialize(php_timezone_obj *tzobj, /*const*/ char *tz TSRMLS_DC) /* {{{ */ { - char *tzid; - - *tzi = NULL; - - if ((tzid = timelib_timezone_id_from_abbr(tz, -1, 0))) { - *tzi = php_date_parse_tzfile(tzid, DATE_TIMEZONEDB TSRMLS_CC); + timelib_time *dummy_t = ecalloc(1, sizeof(timelib_time)); + int dst, not_found; + char *orig_tz = tz; + + dummy_t->z = timelib_parse_zone(&tz, &dst, dummy_t, ¬_found, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper); + if (not_found) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or bad timezone (%s)", orig_tz); + efree(dummy_t); + return FAILURE; } else { - *tzi = php_date_parse_tzfile(tz, DATE_TIMEZONEDB TSRMLS_CC); - } - - if (*tzi) { + set_timezone_from_timelib_time(tzobj, dummy_t); + efree(dummy_t); return SUCCESS; - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or bad timezone (%s)", tz); - return FAILURE; } } /* }}} */ @@ -3590,19 +3638,15 @@ PHP_FUNCTION(timezone_open) { char *tz; int tz_len; - timelib_tzinfo *tzi = NULL; php_timezone_obj *tzobj; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &tz, &tz_len) == FAILURE) { RETURN_FALSE; } - if (SUCCESS != timezone_initialize(&tzi, tz TSRMLS_CC)) { + tzobj = Z_PHPTIMEZONE_P(php_date_instantiate(date_ce_timezone, return_value TSRMLS_CC)); + if (SUCCESS != timezone_initialize(tzobj, tz TSRMLS_CC)) { RETURN_FALSE; } - tzobj = Z_PHPTIMEZONE_P(php_date_instantiate(date_ce_timezone, return_value TSRMLS_CC)); - tzobj->type = TIMELIB_ZONETYPE_ID; - tzobj->tzi.tz = tzi; - tzobj->initialized = 1; } /* }}} */ @@ -3613,18 +3657,13 @@ PHP_METHOD(DateTimeZone, __construct) { char *tz; int tz_len; - timelib_tzinfo *tzi = NULL; php_timezone_obj *tzobj; 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, "s", &tz, &tz_len)) { - if (SUCCESS == timezone_initialize(&tzi, tz TSRMLS_CC)) { - tzobj = Z_PHPTIMEZONE_P(getThis()); - tzobj->type = TIMELIB_ZONETYPE_ID; - tzobj->tzi.tz = tzi; - tzobj->initialized = 1; -//??? } else { + tzobj = Z_PHPTIMEZONE_P(getThis()); + if (FAILURE == timezone_initialize(tzobj, tz TSRMLS_CC)) { //??? ZVAL_NULL(getThis()); } } @@ -3636,41 +3675,12 @@ static int php_date_timezone_initialize_from_hash(zval **return_value, php_timez { zval *z_timezone; zval *z_timezone_type; - timelib_tzinfo *tzi; - z_timezone_type = zend_hash_str_find(myht, "timezone_type", sizeof("timezone_type")-1); - if (z_timezone_type) { - z_timezone = zend_hash_str_find(myht, "timezone", sizeof("timezone")-1); - if (z_timezone) { + if ((z_timezone_type = zend_hash_str_find(myht, "timezone_type", sizeof("timezone_type")-1)) != NULL) { + if ((z_timezone = zend_hash_str_find(myht, "timezone", sizeof("timezone")-1)) != NULL) { convert_to_long(z_timezone_type); - switch (Z_LVAL_P(z_timezone_type)) { - case TIMELIB_ZONETYPE_OFFSET: { - char *offset, *offset_start; - - offset = emalloc(sizeof(char) * (Z_STRLEN_P(z_timezone) + 1)); - memmove(offset, Z_STRVAL_P(z_timezone), Z_STRLEN_P(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_P(z_timezone) TSRMLS_CC)) { - (*tzobj)->type = TIMELIB_ZONETYPE_ID; - (*tzobj)->tzi.tz = tzi; - (*tzobj)->initialized = 1; - return SUCCESS; - } + if (SUCCESS == timezone_initialize(*tzobj, Z_STRVAL_P(z_timezone) TSRMLS_CC)) { + return SUCCESS; } } } @@ -4942,7 +4952,6 @@ static zval *date_period_read_property(zval *object, zval *member, int type, zen zv = std_object_handlers.read_property(object, member, type, cache_slot, rv TSRMLS_CC); if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJ_HANDLER_P(zv, clone_obj)) { /* defensive copy */ -//??? MAKE_STD_ZVAL(zv); ZVAL_OBJ(zv, Z_OBJ_HANDLER_P(zv, clone_obj)(zv TSRMLS_CC)); } |