derick Fri Apr 25 12:36:11 2008 UTC Added files: (Branch: PHP_5_3) /php-src/ext/date/lib interval.c parse_iso_intervals.c parse_iso_intervals.re /php-src/ext/date/tests bug44742.phpt
Modified files: /php-src NEWS /php-src/ext/date config.m4 php_date.c php_date.h /php-src/ext/date/lib README parse_date.c timelib.c timelib.h timelib_structs.h tm2unixtime.c Log: - Added new date/time functionality: . support for diffing date/times through date_diff() / DateTime::diff(). . added DateInterval class to represent the difference between two date/times. . support for parsing ISO intervals for use with DateInterval. . date_add() / DateTime::add(), date_sub() / DateTime::sub() for applying an interval to an existing date/time. - MFH: Fixed bug #44742 (timezone_offset_get() causes segmentation faults).
http://cvs.php.net/viewvc.cgi/php-src/NEWS?r1=1.2027.2.547.2.965.2.162&r2=1.2027.2.547.2.965.2.163&diff_format=u Index: php-src/NEWS diff -u php-src/NEWS:1.2027.2.547.2.965.2.162 php-src/NEWS:1.2027.2.547.2.965.2.163 --- php-src/NEWS:1.2027.2.547.2.965.2.162 Thu Apr 24 07:45:01 2008 +++ php-src/NEWS Fri Apr 25 12:35:40 2008 @@ -49,6 +49,11 @@ . support for "first/last day of <month>" style texts. . support for date/time strings returned by MS SQL. . support for serialization and unserialization of DateTime objects. + . support for diffing date/times through date_diff() / DateTime::diff(). + . added DateInterval class to represent the difference between two date/times. + . support for parsing ISO intervals for use with DateInterval. + . date_add() / DateTime::add(), date_sub() / DateTime::sub() for applying an + interval to an existing date/time. - Added functionality to SPL extension: . Added SPL to list of standard extensions that cannot be disabled. (Marcus) . Added ability to store associative information with objects in @@ -149,6 +154,7 @@ - Fixed PECL bug #12431 (OCI8 ping functionality is broken). (Oracle Corp.) - Fixed bug #44805 (rename() function is not portable to Windows). (Pierre) +- Fixed bug #44742 (timezone_offset_get() causes segmentation faults). (Derick) - Fixed bug #44648 (Attribute names not checked for wellformedness). (Rob) - Fixed bug #44414 (Incomplete reporting about abstract methods). (Dmitry) - Fixed bug #44390 (mysqli_bind_param/bind_result and Object member variables) http://cvs.php.net/viewvc.cgi/php-src/ext/date/config.m4?r1=1.10.2.2&r2=1.10.2.2.4.1&diff_format=u Index: php-src/ext/date/config.m4 diff -u php-src/ext/date/config.m4:1.10.2.2 php-src/ext/date/config.m4:1.10.2.2.4.1 --- php-src/ext/date/config.m4:1.10.2.2 Mon Dec 19 13:00:32 2005 +++ php-src/ext/date/config.m4 Fri Apr 25 12:35:40 2008 @@ -1,4 +1,4 @@ -dnl $Id: config.m4,v 1.10.2.2 2005/12/19 13:00:32 derick Exp $ +dnl $Id: config.m4,v 1.10.2.2.4.1 2008/04/25 12:35:40 derick Exp $ dnl config.m4 for date extension sinclude(ext/date/lib/timelib.m4) @@ -6,7 +6,7 @@ PHP_DATE_CFLAGS="[EMAIL PROTECTED]@/lib" timelib_sources="lib/astro.c lib/dow.c lib/parse_date.c lib/parse_tz.c - lib/timelib.c lib/tm2unixtime.c lib/unixtime2tm.c" + lib/timelib.c lib/tm2unixtime.c lib/unixtime2tm.c lib/parse_iso_intervals.c lib/interval.c" PHP_NEW_EXTENSION(date, php_date.c $timelib_sources, no,, $PHP_DATE_CFLAGS) http://cvs.php.net/viewvc.cgi/php-src/ext/date/php_date.c?r1=1.43.2.45.2.51.2.29&r2=1.43.2.45.2.51.2.30&diff_format=u Index: php-src/ext/date/php_date.c diff -u php-src/ext/date/php_date.c:1.43.2.45.2.51.2.29 php-src/ext/date/php_date.c:1.43.2.45.2.51.2.30 --- php-src/ext/date/php_date.c:1.43.2.45.2.51.2.29 Mon Mar 31 09:11:30 2008 +++ php-src/ext/date/php_date.c Fri Apr 25 12:35:40 2008 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_date.c,v 1.43.2.45.2.51.2.29 2008/03/31 09:11:30 derick Exp $ */ +/* $Id: php_date.c,v 1.43.2.45.2.51.2.30 2008/04/25 12:35:40 derick Exp $ */ #include "php.h" #include "php_streams.h" @@ -174,9 +174,12 @@ PHP_FE(date_get_last_errors, NULL) PHP_FE(date_format, NULL) PHP_FE(date_modify, NULL) + PHP_FE(date_add, NULL) + PHP_FE(date_sub, NULL) PHP_FE(date_timezone_get, NULL) PHP_FE(date_timezone_set, NULL) PHP_FE(date_offset_get, NULL) + PHP_FE(date_diff, NULL) PHP_FE(date_time_set, NULL) PHP_FE(date_date_set, NULL) @@ -192,6 +195,8 @@ PHP_FE(timezone_identifiers_list, NULL) PHP_FE(timezone_abbreviations_list, NULL) + PHP_FE(date_interval_format, NULL) + /* Options and Configuration */ PHP_FE(date_default_timezone_set, arginfo_date_default_timezone_set) PHP_FE(date_default_timezone_get, arginfo_date_default_timezone_get) @@ -211,6 +216,8 @@ PHP_ME_MAPPING(getLastErrors, date_get_last_errors, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME_MAPPING(format, date_format, NULL, 0) PHP_ME_MAPPING(modify, date_modify, NULL, 0) + PHP_ME_MAPPING(add, date_add, NULL, 0) + PHP_ME_MAPPING(sub, date_sub, NULL, 0) PHP_ME_MAPPING(getTimezone, date_timezone_get, NULL, 0) PHP_ME_MAPPING(setTimezone, date_timezone_set, NULL, 0) PHP_ME_MAPPING(getOffset, date_offset_get, NULL, 0) @@ -219,6 +226,7 @@ PHP_ME_MAPPING(setISODate, date_isodate_set, NULL, 0) PHP_ME_MAPPING(setTimestamp, date_timestamp_set, NULL, 0) PHP_ME_MAPPING(getTimestamp, date_timestamp_get, NULL, 0) + PHP_ME_MAPPING(diff, date_diff, NULL, 0) {NULL, NULL, NULL} }; @@ -232,9 +240,14 @@ {NULL, NULL, NULL} }; +const zend_function_entry date_funcs_interval[] = { + PHP_ME(DateInterval, __construct, NULL, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(format, date_interval_format, NULL, 0) + {NULL, NULL, NULL} +}; + static char* guess_timezone(const timelib_tzdb *tzdb TSRMLS_DC); static void date_register_classes(TSRMLS_D); -static char* guess_timezone(const timelib_tzdb *tzdb TSRMLS_DC); /* }}} */ ZEND_DECLARE_MODULE_GLOBALS(date) @@ -263,13 +276,15 @@ PHP_INI_END() /* }}} */ -zend_class_entry *date_ce_date, *date_ce_timezone; +zend_class_entry *date_ce_date, *date_ce_timezone, *date_ce_interval; static zend_object_handlers date_object_handlers_date; static zend_object_handlers date_object_handlers_timezone; +static zend_object_handlers date_object_handlers_interval; typedef struct _php_date_obj php_date_obj; typedef struct _php_timezone_obj php_timezone_obj; +typedef struct _php_interval_obj php_interval_obj; struct _php_date_obj { zend_object std; @@ -293,6 +308,13 @@ } tzi; }; +struct _php_interval_obj { + zend_object std; + timelib_rel_time *diff; + HashTable *props; + int initialized; +}; + #define DATE_SET_CONTEXT \ zval *object; \ object = getThis(); \ @@ -319,12 +341,21 @@ static void date_object_free_storage_date(void *object TSRMLS_DC); static void date_object_free_storage_timezone(void *object TSRMLS_DC); +static void date_object_free_storage_interval(void *object TSRMLS_DC); + static zend_object_value date_object_new_date(zend_class_entry *class_type TSRMLS_DC); static zend_object_value date_object_new_timezone(zend_class_entry *class_type TSRMLS_DC); +static zend_object_value date_object_new_interval(zend_class_entry *class_type TSRMLS_DC); + static zend_object_value date_object_clone_date(zval *this_ptr TSRMLS_DC); +static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC); +static zend_object_value date_object_clone_interval(zval *this_ptr TSRMLS_DC); + static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC); static HashTable *date_object_get_properties(zval *object TSRMLS_DC); -static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC); + +zval *date_interval_read_property(zval *object, zval *member, int type TSRMLS_DC); +void date_interval_write_property(zval *object, zval *member, zval *value TSRMLS_DC); /* This is need to ensure that session extension request shutdown occurs 1st, because it uses the date extension */ static const zend_module_dep date_deps[] = { @@ -1520,7 +1551,7 @@ static void date_register_classes(TSRMLS_D) { - zend_class_entry ce_date, ce_timezone; + zend_class_entry ce_date, ce_timezone, ce_interval; INIT_CLASS_ENTRY(ce_date, "DateTime", date_funcs_date); ce_date.create_object = date_object_new_date; @@ -1568,6 +1599,14 @@ REGISTER_TIMEZONE_CLASS_CONST_STRING("UTC", PHP_DATE_TIMEZONE_GROUP_UTC); REGISTER_TIMEZONE_CLASS_CONST_STRING("ALL", PHP_DATE_TIMEZONE_GROUP_ALL); REGISTER_TIMEZONE_CLASS_CONST_STRING("ALL_WITH_BC", PHP_DATE_TIMEZONE_GROUP_ALL_W_BC); + + INIT_CLASS_ENTRY(ce_interval, "DateInterval", date_funcs_interval); + ce_interval.create_object = date_object_new_interval; + date_ce_interval = zend_register_internal_class_ex(&ce_interval, NULL, NULL TSRMLS_CC); + memcpy(&date_object_handlers_interval, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + date_object_handlers_interval.clone_obj = date_object_clone_interval; + date_object_handlers_interval.read_property = date_interval_read_property; + date_object_handlers_interval.write_property = date_interval_write_property; } static inline zend_object_value date_object_new_date_ex(zend_class_entry *class_type, php_date_obj **ptr TSRMLS_DC) @@ -1743,6 +1782,44 @@ return new_ov; } +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; + zend_object_value retval; + zval *tmp; + + intern = emalloc(sizeof(php_interval_obj)); + memset(intern, 0, sizeof(php_interval_obj)); + if (ptr) { + *ptr = intern; + } + + zend_object_std_init(&intern->std, class_type TSRMLS_CC); + zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + + 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); + retval.handlers = &date_object_handlers_interval; + + return retval; +} + +static zend_object_value date_object_new_interval(zend_class_entry *class_type TSRMLS_DC) +{ + return date_object_new_interval_ex(class_type, NULL TSRMLS_CC); +} + +static zend_object_value date_object_clone_interval(zval *this_ptr TSRMLS_DC) +{ + php_interval_obj *new_obj = NULL; + php_interval_obj *old_obj = (php_interval_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC); + zend_object_value new_ov = date_object_new_interval_ex(old_obj->std.ce, &new_obj TSRMLS_CC); + + zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC); + + /** FIX ME ADD CLONE STUFF **/ + return new_ov; +} + static void date_object_free_storage_date(void *object TSRMLS_DC) { php_date_obj *intern = (php_date_obj *)object; @@ -1769,6 +1846,15 @@ efree(object); } +static void date_object_free_storage_interval(void *object TSRMLS_DC) +{ + php_interval_obj *intern = (php_interval_obj *)object; + + timelib_rel_time_dtor(intern->diff); + zend_object_std_dtor(&intern->std TSRMLS_CC); + efree(object); +} + /* Advanced Interface */ static zval * date_instantiate(zend_class_entry *pce, zval *object TSRMLS_DC) { @@ -2233,6 +2319,82 @@ } /* }}} */ +/* {{{ proto void date_add(DateTime object, DateInterval interval) + Adds an interval to the current date in object. +*/ +PHP_FUNCTION(date_add) +{ + zval *object, *interval; + php_date_obj *dateobj; + php_interval_obj *intobj; + int bias = 1; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) { + RETURN_FALSE; + } + 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->invert) { + bias = -1; + } + + dateobj->time->relative.y = intobj->diff->y * bias; + dateobj->time->relative.m = intobj->diff->m * bias; + dateobj->time->relative.d = intobj->diff->d * bias; + dateobj->time->relative.h = intobj->diff->h * bias; + dateobj->time->relative.i = intobj->diff->i * bias; + dateobj->time->relative.s = intobj->diff->s * bias; + dateobj->time->relative.weekday = 0; + dateobj->time->have_relative = 1; + dateobj->time->have_weekday_relative = 0; + dateobj->time->sse_uptodate = 0; + + timelib_update_ts(dateobj->time, NULL); + timelib_update_from_sse(dateobj->time); +} +/* }}} */ + +/* {{{ proto void date_sub(DateTime object, DateInterval interval) + Subtracts an interval to the current date in object. +*/ +PHP_FUNCTION(date_sub) +{ + zval *object, *interval; + php_date_obj *dateobj; + php_interval_obj *intobj; + int bias = 1; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) { + RETURN_FALSE; + } + 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->invert) { + bias = -1; + } + + dateobj->time->relative.y = 0 - (intobj->diff->y * bias); + dateobj->time->relative.m = 0 - (intobj->diff->m * bias); + dateobj->time->relative.d = 0 - (intobj->diff->d * bias); + dateobj->time->relative.h = 0 - (intobj->diff->h * bias); + dateobj->time->relative.i = 0 - (intobj->diff->i * bias); + dateobj->time->relative.s = 0 - (intobj->diff->s * bias); + dateobj->time->relative.weekday = 0; + dateobj->time->have_relative = 1; + dateobj->time->have_weekday_relative = 0; + dateobj->time->sse_uptodate = 0; + + timelib_update_ts(dateobj->time, NULL); + timelib_update_from_sse(dateobj->time); +} +/* }}} */ + /* {{{ proto DateTimeZone date_timezone_get(DateTime object) Return new DateTimeZone object relative to give DateTime */ @@ -2444,6 +2606,36 @@ } /* }}} */ +/* {{{ proto DateInterval date_diff(DateTime object [, bool absolute]) + Returns the difference between two DateTime objects. +*/ +PHP_FUNCTION(date_diff) +{ + zval *object1, *object2; + php_date_obj *dateobj1, *dateobj2; + php_interval_obj *interval; + long absolute = 0; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO|l", &object1, date_ce_date, &object2, date_ce_date, &absolute) == FAILURE) { + RETURN_FALSE; + } + dateobj1 = (php_date_obj *) zend_object_store_get_object(object1 TSRMLS_CC); + dateobj2 = (php_date_obj *) zend_object_store_get_object(object2 TSRMLS_CC); + DATE_CHECK_INITIALIZED(dateobj1->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj2->time, DateTime); + timelib_update_ts(dateobj1->time, NULL); + timelib_update_ts(dateobj2->time, NULL); + + date_instantiate(date_ce_interval, return_value TSRMLS_CC); + interval = zend_object_store_get_object(return_value TSRMLS_CC); + interval->diff = timelib_diff(dateobj1->time, dateobj2->time); + if (absolute) { + interval->diff->invert = 0; + } + interval->initialized = 1; +} +/* }}} */ + static int timezone_initialize(timelib_tzinfo **tzi, /*const*/ char *tz TSRMLS_DC) { char *tzid; @@ -2464,6 +2656,119 @@ } } +static int date_interval_initialize(timelib_rel_time **rt, /*const*/ char *format, int format_length TSRMLS_DC) +{ + timelib_time *b = NULL, *e = NULL; + timelib_rel_time *p = NULL; + int r = 0; + int retval = 0; + struct timelib_error_container *errors; + + timelib_strtointerval(format, format_length, &b, &e, &p, &r, &errors); + + if (errors->error_count > 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or bad format (%s)", format); + retval = FAILURE; + } else { + *rt = p; + retval = SUCCESS; + } + timelib_error_container_dtor(errors); + return retval; +} + +/* {{{ date_interval_read_property */ +zval *date_interval_read_property(zval *object, zval *member, int type TSRMLS_DC) +{ + php_interval_obj *obj; + zval *retval; + zval tmp_member; + timelib_sll value = -1; + + if (member->type != IS_STRING) { + tmp_member = *member; + zval_copy_ctor(&tmp_member); + convert_to_string(&tmp_member); + member = &tmp_member; + } + + obj = (php_interval_obj *)zend_objects_get_address(object TSRMLS_CC); + +#define GET_VALUE_FROM_STRUCT(n,m) \ + if (strcmp(Z_STRVAL_P(member), m) == 0) { \ + value = obj->diff->n; \ + } + GET_VALUE_FROM_STRUCT(y, "y"); + GET_VALUE_FROM_STRUCT(m, "m"); + GET_VALUE_FROM_STRUCT(d, "d"); + GET_VALUE_FROM_STRUCT(h, "h"); + GET_VALUE_FROM_STRUCT(i, "i"); + GET_VALUE_FROM_STRUCT(s, "s"); + GET_VALUE_FROM_STRUCT(invert, "invert"); + GET_VALUE_FROM_STRUCT(days, "days"); + + if (value == -1) { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unknown property (%s)", Z_STRVAL_P(member)); + } + + ALLOC_INIT_ZVAL(retval); + ZVAL_LONG(retval, value); + + if (member == &tmp_member) { + zval_dtor(member); + } + + return retval; +} +/* }}} */ + +/* {{{ date_interval_write_property */ +void date_interval_write_property(zval *object, zval *member, zval *value TSRMLS_DC) +{ + php_interval_obj *obj; + zval tmp_member, tmp_value; + + if (member->type != IS_STRING) { + tmp_member = *member; + zval_copy_ctor(&tmp_member); + convert_to_string(&tmp_member); + member = &tmp_member; + } + obj = (php_interval_obj *)zend_objects_get_address(object TSRMLS_CC); + +#define SET_VALUE_FROM_STRUCT(n,m) \ + if (strcmp(Z_STRVAL_P(member), m) == 0) { \ + if (value->type != IS_LONG) { \ + tmp_value = *value; \ + zval_copy_ctor(&tmp_value); \ + convert_to_long(&tmp_value); \ + value = &tmp_value; \ + } \ + obj->diff->n = Z_LVAL_P(value); \ + if (value == &tmp_value) { \ + zval_dtor(value); \ + } \ + } + + SET_VALUE_FROM_STRUCT(y, "y"); + SET_VALUE_FROM_STRUCT(m, "m"); + SET_VALUE_FROM_STRUCT(d, "d"); + SET_VALUE_FROM_STRUCT(h, "h"); + SET_VALUE_FROM_STRUCT(i, "i"); + SET_VALUE_FROM_STRUCT(s, "s"); + SET_VALUE_FROM_STRUCT(invert, "invert"); + + if (value == -1) { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unknown property (%s)", Z_STRVAL_P(member)); + } + + if (member == &tmp_member) { + zval_dtor(member); + } +} +/* }}} */ + + /* {{{ proto DateTimeZone timezone_open(string timezone) Returns new DateTimeZone object */ @@ -2591,9 +2896,19 @@ dateobj = (php_date_obj *) zend_object_store_get_object(dateobject TSRMLS_CC); DATE_CHECK_INITIALIZED(dateobj->time, DateTime); - offset = timelib_get_time_zone_info(dateobj->time->sse, tzobj->tzi.tz); - RETVAL_LONG(offset->offset); - timelib_time_offset_dtor(offset); + switch (tzobj->type) { + case TIMELIB_ZONETYPE_ID: + offset = timelib_get_time_zone_info(dateobj->time->sse, tzobj->tzi.tz); + RETVAL_LONG(offset->offset); + timelib_time_offset_dtor(offset); + break; + case TIMELIB_ZONETYPE_OFFSET: + RETURN_LONG(tzobj->tzi.utc_offset * -60); + break; + case TIMELIB_ZONETYPE_ABBR: + RETURN_LONG((tzobj->tzi.z.utc_offset - (tzobj->tzi.z.dst*60)) * -60); + break; + } } /* }}} */ @@ -2679,6 +2994,105 @@ } /* }}} */ +/* {{{ proto DateInterval::__construct([string interval_spec]) + Creates new DateInterval object. +*/ +PHP_METHOD(DateInterval, __construct) +{ + char *interval_string = NULL; + int interval_string_length; + php_interval_obj *diobj; + timelib_rel_time *reltime; + + php_set_error_handling(EH_THROW, NULL TSRMLS_CC); + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &interval_string, &interval_string_length) == SUCCESS) { + if (date_interval_initialize(&reltime, interval_string, interval_string_length TSRMLS_CC) == SUCCESS) { + diobj = zend_object_store_get_object(getThis() TSRMLS_CC); + diobj->diff = reltime; + diobj->initialized = 1; + } else { + ZVAL_NULL(getThis()); + } + } + php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); +} +/* }}} */ + +/* {{{ date_interval_format - */ +static char *date_interval_format(char *format, int format_len, timelib_rel_time *t) +{ + smart_str string = {0}; + int i, length, have_format_spec = 0; + char buffer[33]; + + if (!format_len) { + return estrdup(""); + } + + for (i = 0; i < format_len; i++) { + if (have_format_spec) { + switch (format[i]) { + case 'Y': length = slprintf(buffer, 32, "%02d", (int) t->y); break; + case 'y': length = slprintf(buffer, 32, "%d", (int) t->y); break; + + case 'M': length = slprintf(buffer, 32, "%02d", (int) t->m); break; + case 'm': length = slprintf(buffer, 32, "%d", (int) t->m); break; + + case 'D': length = slprintf(buffer, 32, "%02d", (int) t->d); break; + case 'd': length = slprintf(buffer, 32, "%d", (int) t->d); break; + + case 'H': length = slprintf(buffer, 32, "%02d", (int) t->h); break; + case 'h': length = slprintf(buffer, 32, "%d", (int) t->h); break; + + case 'I': length = slprintf(buffer, 32, "%02d", (int) t->i); break; + case 'i': length = slprintf(buffer, 32, "%d", (int) t->i); break; + + case 'S': length = slprintf(buffer, 32, "%02d", (int) t->s); break; + case 's': length = slprintf(buffer, 32, "%d", (int) t->s); break; + + case 'a': length = slprintf(buffer, 32, "%d", (int) t->days); break; + case 'r': length = slprintf(buffer, 32, "%s", t->invert ? "-" : ""); break; + case 'R': length = slprintf(buffer, 32, "%c", t->invert ? '-' : '+'); break; + + case '%': length = slprintf(buffer, 32, "%%"); break; + default: buffer[0] = '%'; buffer[1] = format[i]; buffer[2] = '\0'; length = 2; break; + } + smart_str_appendl(&string, buffer, length); + have_format_spec = 0; + } else { + if (format[i] == '%') { + have_format_spec = 1; + } else { + smart_str_appendc(&string, format[i]); + } + } + } + + smart_str_0(&string); + + return string.c; +} +/* }}} */ + +/* {{{ proto string date_interval_format(DateInterval object) + Formats the interval. +*/ +PHP_FUNCTION(date_interval_format) +{ + zval *object; + php_interval_obj *diobj; + char *format; + int format_len; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_interval, &format, &format_len) == FAILURE) { + RETURN_FALSE; + } + diobj = (php_interval_obj *) zend_object_store_get_object(object TSRMLS_CC); + DATE_CHECK_INITIALIZED(diobj->initialized, DateInterval); + + RETURN_STRING(date_interval_format(format, format_len, diobj->diff), 0); +} +/* }}} */ static int check_id_allowed(char *id, long what) { if (what & PHP_DATE_TIMEZONE_GROUP_AFRICA && strncasecmp(id, "Africa/", 7) == 0) return 1; http://cvs.php.net/viewvc.cgi/php-src/ext/date/php_date.h?r1=1.17.2.11.2.3.2.5&r2=1.17.2.11.2.3.2.6&diff_format=u Index: php-src/ext/date/php_date.h diff -u php-src/ext/date/php_date.h:1.17.2.11.2.3.2.5 php-src/ext/date/php_date.h:1.17.2.11.2.3.2.6 --- php-src/ext/date/php_date.h:1.17.2.11.2.3.2.5 Fri Mar 14 16:19:52 2008 +++ php-src/ext/date/php_date.h Fri Apr 25 12:35:40 2008 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_date.h,v 1.17.2.11.2.3.2.5 2008/03/14 16:19:52 derick Exp $ */ +/* $Id: php_date.h,v 1.17.2.11.2.3.2.6 2008/04/25 12:35:40 derick Exp $ */ #ifndef PHP_DATE_H #define PHP_DATE_H @@ -57,9 +57,12 @@ PHP_FUNCTION(date_get_last_errors); PHP_FUNCTION(date_format); PHP_FUNCTION(date_modify); +PHP_FUNCTION(date_add); +PHP_FUNCTION(date_sub); PHP_FUNCTION(date_timezone_get); PHP_FUNCTION(date_timezone_set); PHP_FUNCTION(date_offset_get); +PHP_FUNCTION(date_diff); PHP_FUNCTION(date_time_set); PHP_FUNCTION(date_date_set); @@ -76,6 +79,9 @@ PHP_FUNCTION(timezone_identifiers_list); PHP_FUNCTION(timezone_abbreviations_list); +PHP_METHOD(DateInterval, __construct); +PHP_FUNCTION(date_interval_format); + /* Options and Configuration */ PHP_FUNCTION(date_default_timezone_set); PHP_FUNCTION(date_default_timezone_get); http://cvs.php.net/viewvc.cgi/php-src/ext/date/lib/README?r1=1.4.2.2&r2=1.4.2.2.4.1&diff_format=u Index: php-src/ext/date/lib/README diff -u php-src/ext/date/lib/README:1.4.2.2 php-src/ext/date/lib/README:1.4.2.2.4.1 --- php-src/ext/date/lib/README:1.4.2.2 Thu Nov 17 12:33:36 2005 +++ php-src/ext/date/lib/README Fri Apr 25 12:35:40 2008 @@ -3,4 +3,5 @@ Make sure you use re2c 0.9.10 or higher: -/dat/dev/sf/re2c/re2c -d -b -o ext/date/lib/parse_date.c ext/date/lib/parse_date.re +re2c -d -b -o ext/date/lib/parse_date.c ext/date/lib/parse_date.re +re2c -d -b -o ext/date/lib/parse_iso_intervals.c ext/date/lib/parse_iso_intervals.re http://cvs.php.net/viewvc.cgi/php-src/ext/date/lib/parse_date.c?r1=1.29.2.30.2.14.2.11&r2=1.29.2.30.2.14.2.12&diff_format=u Index: php-src/ext/date/lib/parse_date.c diff -u php-src/ext/date/lib/parse_date.c:1.29.2.30.2.14.2.11 php-src/ext/date/lib/parse_date.c:1.29.2.30.2.14.2.12 --- php-src/ext/date/lib/parse_date.c:1.29.2.30.2.14.2.11 Sun Mar 23 15:48:10 2008 +++ php-src/ext/date/lib/parse_date.c Fri Apr 25 12:35:40 2008 @@ -1,4 +1,4 @@ -/* Generated by re2c 0.13.3 on Sun Mar 23 11:46:55 2008 */ +/* Generated by re2c 0.13.3 on Mon Apr 7 19:58:18 2008 */ #line 1 "ext/date/lib/parse_date.re" /* +----------------------------------------------------------------------+ @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: parse_date.c,v 1.29.2.30.2.14.2.11 2008/03/23 15:48:10 iliaa Exp $ */ +/* $Id: parse_date.c,v 1.29.2.30.2.14.2.12 2008/04/25 12:35:40 derick Exp $ */ #include "timelib.h" http://cvs.php.net/viewvc.cgi/php-src/ext/date/lib/timelib.c?r1=1.7.2.4.2.6.2.2&r2=1.7.2.4.2.6.2.3&diff_format=u Index: php-src/ext/date/lib/timelib.c diff -u php-src/ext/date/lib/timelib.c:1.7.2.4.2.6.2.2 php-src/ext/date/lib/timelib.c:1.7.2.4.2.6.2.3 --- php-src/ext/date/lib/timelib.c:1.7.2.4.2.6.2.2 Sun Feb 3 14:15:07 2008 +++ php-src/ext/date/lib/timelib.c Fri Apr 25 12:35:57 2008 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: timelib.c,v 1.7.2.4.2.6.2.2 2008/02/03 14:15:07 derick Exp $ */ +/* $Id: timelib.c,v 1.7.2.4.2.6.2.3 2008/04/25 12:35:57 derick Exp $ */ #include "timelib.h" #include <ctype.h> @@ -38,6 +38,14 @@ return t; } +timelib_rel_time* timelib_rel_time_ctor(void) +{ + timelib_rel_time *t; + t = calloc(1, sizeof(timelib_rel_time)); + + return t; +} + void timelib_time_tz_abbr_update(timelib_time* tm, char* tz_abbr) { unsigned int i; @@ -55,6 +63,11 @@ TIMELIB_TIME_FREE(t); } +void timelib_rel_time_dtor(timelib_rel_time* t) +{ + TIMELIB_TIME_FREE(t); +} + timelib_time_offset* timelib_time_offset_ctor(void) { timelib_time_offset *t; @@ -114,6 +127,7 @@ TIMELIB_TIME_FREE(tz->timezone_abbr); TIMELIB_TIME_FREE(tz->leap_times); TIMELIB_TIME_FREE(tz); + tz = NULL; } char *timelib_get_tz_abbr_ptr(timelib_time *t) @@ -228,3 +242,20 @@ printf("\n"); } +void timelib_dump_rel_time(timelib_rel_time *d) +{ + printf("%3lldY %3lldM %3lldD / %3lldH %3lldM %3lldS (days: %lld)%s", + d->y, d->m, d->d, d->h, d->i, d->s, d->days, d->invert ? " inverted" : ""); + if (d->first_last_day_of != 0) { + switch (d->first_last_day_of) { + case 1: + printf(" / first day of"); + break; + case 2: + printf(" / last day of"); + break; + } + } + printf("\n"); +} + http://cvs.php.net/viewvc.cgi/php-src/ext/date/lib/timelib.h?r1=1.10.2.11.2.3.2.3&r2=1.10.2.11.2.3.2.4&diff_format=u Index: php-src/ext/date/lib/timelib.h diff -u php-src/ext/date/lib/timelib.h:1.10.2.11.2.3.2.3 php-src/ext/date/lib/timelib.h:1.10.2.11.2.3.2.4 --- php-src/ext/date/lib/timelib.h:1.10.2.11.2.3.2.3 Fri Feb 22 09:47:19 2008 +++ php-src/ext/date/lib/timelib.h Fri Apr 25 12:35:57 2008 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: timelib.h,v 1.10.2.11.2.3.2.3 2008/02/22 09:47:19 derick Exp $ */ +/* $Id: timelib.h,v 1.10.2.11.2.3.2.4 2008/04/25 12:35:57 derick Exp $ */ #ifndef __TIMELIB_H__ #define __TIMELIB_H__ @@ -62,8 +62,16 @@ char *timelib_timezone_id_from_abbr(const char *abbr, long gmtoffset, int isdst); const timelib_tz_lookup_table *timelib_timezone_abbreviations_list(void); +/* From parse_iso_intervals.re */ +void timelib_strtointerval(char *s, int len, + timelib_time **begin, timelib_time **end, + timelib_rel_time **period, int *recurrences, + struct timelib_error_container **errors); + + /* From tm2unixtime.c */ void timelib_update_ts(timelib_time* time, timelib_tzinfo* tzi); +void timelib_do_rel_normalize(timelib_time *base, timelib_rel_time *rt); /* From unixtime2tm.c */ int timelib_apply_localtime(timelib_time *t, unsigned int localtime); @@ -89,6 +97,9 @@ void timelib_tzinfo_dtor(timelib_tzinfo *tz); timelib_tzinfo* timelib_tzinfo_clone(timelib_tzinfo *tz); +timelib_rel_time* timelib_rel_time_ctor(void); +void timelib_rel_time_dtor(timelib_rel_time* t); + timelib_time* timelib_time_ctor(void); void timelib_time_set_option(timelib_time* tm, int option, void* option_value); void timelib_time_dtor(timelib_time* t); @@ -100,6 +111,7 @@ signed long timelib_date_to_int(timelib_time *d, int *error); void timelib_dump_date(timelib_time *d, int options); +void timelib_dump_rel_time(timelib_rel_time *d); void timelib_decimal_hour_to_hms(double h, int *hour, int *min, int *sec); @@ -107,4 +119,7 @@ double timelib_ts_to_juliandate(timelib_sll ts); int timelib_astro_rise_set_altitude(timelib_time *time, double lon, double lat, double altit, int upper_limb, double *h_rise, double *h_set, timelib_sll *ts_rise, timelib_sll *ts_set, timelib_sll *ts_transit); +/* from interval.c */ +timelib_rel_time *timelib_diff(timelib_time *one, timelib_time *two); + #endif http://cvs.php.net/viewvc.cgi/php-src/ext/date/lib/timelib_structs.h?r1=1.13.2.6.2.3.2.3&r2=1.13.2.6.2.3.2.4&diff_format=u Index: php-src/ext/date/lib/timelib_structs.h diff -u php-src/ext/date/lib/timelib_structs.h:1.13.2.6.2.3.2.3 php-src/ext/date/lib/timelib_structs.h:1.13.2.6.2.3.2.4 --- php-src/ext/date/lib/timelib_structs.h:1.13.2.6.2.3.2.3 Thu Mar 13 15:59:48 2008 +++ php-src/ext/date/lib/timelib_structs.h Fri Apr 25 12:35:58 2008 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: timelib_structs.h,v 1.13.2.6.2.3.2.3 2008/03/13 15:59:48 derick Exp $ */ +/* $Id: timelib_structs.h,v 1.13.2.6.2.3.2.4 2008/04/25 12:35:58 derick Exp $ */ #ifndef __TIMELIB_STRUCTS_H__ #define __TIMELIB_STRUCTS_H__ @@ -124,6 +124,8 @@ int weekday_behavior; /* 0: the current day should *not* be counted when advancing forwards; 1: the current day *should* be counted */ int first_last_day_of; + int invert; /* Whether the difference should be inverted */ + timelib_sll days; /* Contains the number of *days*, instead of Y-M-D differences */ } timelib_rel_time; typedef struct timelib_time_offset { http://cvs.php.net/viewvc.cgi/php-src/ext/date/lib/tm2unixtime.c?r1=1.13.2.3.2.2.2.3&r2=1.13.2.3.2.2.2.4&diff_format=u Index: php-src/ext/date/lib/tm2unixtime.c diff -u php-src/ext/date/lib/tm2unixtime.c:1.13.2.3.2.2.2.3 php-src/ext/date/lib/tm2unixtime.c:1.13.2.3.2.2.2.4 --- php-src/ext/date/lib/tm2unixtime.c:1.13.2.3.2.2.2.3 Sun Feb 3 14:15:07 2008 +++ php-src/ext/date/lib/tm2unixtime.c Fri Apr 25 12:35:58 2008 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: tm2unixtime.c,v 1.13.2.3.2.2.2.3 2008/02/03 14:15:07 derick Exp $ */ +/* $Id: tm2unixtime.c,v 1.13.2.3.2.2.2.4 2008/04/25 12:35:58 derick Exp $ */ #include "timelib.h" @@ -49,6 +49,41 @@ return 0; } +static int do_range_limit_days_relative(timelib_sll *base_y, timelib_sll *base_m, timelib_sll *y, timelib_sll *m, timelib_sll *d) +{ + timelib_sll leapyear; + timelib_sll days_this_month; + timelib_sll next_month, next_year; + timelib_sll days_next_month; + + do_range_limit(1, 13, 12, base_m, base_y); + + leapyear = timelib_is_leap(*base_y); + days_this_month = leapyear ? days_in_month_leap[*base_m] : days_in_month[*base_m]; + next_month = (*base_m) + 1; + + if (next_month > 12) { + next_month -= 12; + next_year = (*base_y) + 1; + } else { + next_year = (*base_y); + } + leapyear = timelib_is_leap(next_year); + days_next_month = leapyear ? days_in_month_leap[next_month] : days_in_month[next_month]; + + if (*d < 0) { + *d += days_this_month; + (*m)--; + return 1; + } + if (*d > days_next_month) { + *d -= days_next_month; + (*m)++; + return 1; + } + return 0; +} + static int do_range_limit_days(timelib_sll *y, timelib_sll *m, timelib_sll *d) { timelib_sll leapyear; @@ -101,6 +136,17 @@ time->have_weekday_relative = 0; } +void timelib_do_rel_normalize(timelib_time *base, timelib_rel_time *rt) +{ + do {} while (do_range_limit(0, 60, 60, &rt->s, &rt->i)); + do {} while (do_range_limit(0, 60, 60, &rt->i, &rt->h)); + do {} while (do_range_limit(0, 24, 24, &rt->h, &rt->d)); + do {} while (do_range_limit(0, 12, 12, &rt->m, &rt->y)); + + do {} while (do_range_limit_days_relative(&base->y, &base->m, &rt->y, &rt->m, &rt->d)); + do {} while (do_range_limit(0, 12, 12, &rt->m, &rt->y)); +} + static void do_normalize(timelib_time* time) { do {} while (do_range_limit(0, 60, 60, &time->s, &time->i)); @@ -293,7 +339,20 @@ } timelib_time_offset_dtor(before); timelib_time_offset_dtor(after); - + + { + timelib_time_offset *gmt_offset; + + gmt_offset = timelib_get_time_zone_info(tz->sse + tmp, tzi); + tz->z = gmt_offset->offset; + + tz->dst = gmt_offset->is_dst; + if (tz->tz_abbr) { + free(tz->tz_abbr); + } + tz->tz_abbr = strdup(gmt_offset->abbr); + timelib_time_offset_dtor(gmt_offset); + } return tmp; } } http://cvs.php.net/viewvc.cgi/php-src/ext/date/lib/interval.c?view=markup&rev=1.1 Index: php-src/ext/date/lib/interval.c +++ php-src/ext/date/lib/interval.c http://cvs.php.net/viewvc.cgi/php-src/ext/date/lib/parse_iso_intervals.c?view=markup&rev=1.1 Index: php-src/ext/date/lib/parse_iso_intervals.c +++ php-src/ext/date/lib/parse_iso_intervals.c http://cvs.php.net/viewvc.cgi/php-src/ext/date/lib/parse_iso_intervals.re?view=markup&rev=1.1 Index: php-src/ext/date/lib/parse_iso_intervals.re +++ php-src/ext/date/lib/parse_iso_intervals.re http://cvs.php.net/viewvc.cgi/php-src/ext/date/tests/bug44742.phpt?view=markup&rev=1.1 Index: php-src/ext/date/tests/bug44742.phpt +++ php-src/ext/date/tests/bug44742.phpt
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php