From 1dd80b06f1d9bb1a39f2693b24013022ba18cd88 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 21 Jul 2013 16:22:44 +0100 Subject: [PATCH 1/6] Add DateInterval::add --- ext/date/lib/interval.c | 22 +++++++++++++++++++++ ext/date/lib/timelib.h | 1 + ext/date/lib/tm2unixtime.c | 6 ++++-- ext/date/php_date.c | 40 ++++++++++++++++++++++++++++++++++++++ ext/date/php_date.h | 1 + 5 files changed, 68 insertions(+), 2 deletions(-) diff --git a/ext/date/lib/interval.c b/ext/date/lib/interval.c index 96867ba2b797a..8cf7f3e5e2cfd 100644 --- a/ext/date/lib/interval.c +++ b/ext/date/lib/interval.c @@ -70,3 +70,25 @@ timelib_rel_time *timelib_diff(timelib_time *one, timelib_time *two) return rt; } + +timelib_rel_time *timelib_rel_add(timelib_rel_time *one, timelib_rel_time *two) +{ + timelib_rel_time *rt; + + if (one->have_weekday_relative || one->have_special_relative || + two->have_weekday_relative || two->have_special_relative) { + return NULL; + } + + rt = timelib_rel_time_ctor(); + rt->y = two->y + one->y; + rt->m = two->m + one->m; + rt->d = two->d + one->d; + rt->h = two->h + one->h; + rt->i = two->i + one->i; + rt->s = two->s + one->s; + + timelib_do_rel_normalize(NULL, rt); + + return rt; +} diff --git a/ext/date/lib/timelib.h b/ext/date/lib/timelib.h index dfb7dc0300763..e4341395ee0f3 100644 --- a/ext/date/lib/timelib.h +++ b/ext/date/lib/timelib.h @@ -138,5 +138,6 @@ int timelib_astro_rise_set_altitude(timelib_time *time, double lon, double lat, /* from interval.c */ timelib_rel_time *timelib_diff(timelib_time *one, timelib_time *two); +timelib_rel_time *timelib_rel_add(timelib_rel_time *one, timelib_rel_time *two); #endif diff --git a/ext/date/lib/tm2unixtime.c b/ext/date/lib/tm2unixtime.c index 23fe202ba9f44..8e9d7ee3d19ad 100644 --- a/ext/date/lib/tm2unixtime.c +++ b/ext/date/lib/tm2unixtime.c @@ -175,8 +175,10 @@ void timelib_do_rel_normalize(timelib_time *base, timelib_rel_time *rt) 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_range_limit_days_relative(&base->y, &base->m, &rt->y, &rt->m, &rt->d, rt->invert); - do {} while (do_range_limit(0, 12, 12, &rt->m, &rt->y)); + if (base) { + do_range_limit_days_relative(&base->y, &base->m, &rt->y, &rt->m, &rt->d, rt->invert); + do {} while (do_range_limit(0, 12, 12, &rt->m, &rt->y)); + } } void timelib_do_normalize(timelib_time* time) diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 0f8822a906006..3f252e35a6743 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -367,6 +367,10 @@ ZEND_BEGIN_ARG_INFO(arginfo_date_method_interval_format, 0) ZEND_ARG_INFO(0, format) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO(arginfo_date_method_interval_add, 0) + ZEND_ARG_INFO(0, interval) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_date_period_construct, 0, 0, 3) ZEND_ARG_INFO(0, start) ZEND_ARG_INFO(0, interval) @@ -376,6 +380,11 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_construct, 0, 0, 0) ZEND_ARG_INFO(0, interval_spec) ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_date_interval_add, 0) + ZEND_ARG_INFO(0, interval1) + ZEND_ARG_INFO(0, interval2) +ZEND_END_ARG_INFO() /* }}} */ /* {{{ Function table */ @@ -432,6 +441,7 @@ const zend_function_entry date_functions[] = { PHP_FE(date_interval_create_from_date_string, arginfo_date_interval_create_from_date_string) PHP_FE(date_interval_format, arginfo_date_interval_format) + PHP_FE(date_interval_add, arginfo_date_interval_add) /* Options and Configuration */ PHP_FE(date_default_timezone_set, arginfo_date_default_timezone_set) @@ -516,6 +526,7 @@ const zend_function_entry date_funcs_interval[] = { PHP_ME(DateInterval, __wakeup, NULL, ZEND_ACC_PUBLIC) PHP_ME(DateInterval, __set_state, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME_MAPPING(format, date_interval_format, arginfo_date_method_interval_format, 0) + PHP_ME_MAPPING(add, date_interval_add, arginfo_date_method_interval_add, 0) PHP_ME_MAPPING(createFromDateString, date_interval_create_from_date_string, arginfo_date_interval_create_from_date_string, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_FE_END }; @@ -4347,6 +4358,35 @@ PHP_FUNCTION(date_interval_format) } /* }}} */ +/* {{{ proto string date_interval_add(DateInterval interval1, DateInterval interval2) + Add the intervals. +*/ +PHP_FUNCTION(date_interval_add) +{ + zval *zi1, *zi2; + php_interval_obj *diobj1, *diobj2, *diobjr; + timelib_rel_time *rtime; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &zi1, date_ce_interval, &zi2, date_ce_interval) == FAILURE) { + RETURN_FALSE; + } + diobj1 = (php_interval_obj *) zend_object_store_get_object(zi1 TSRMLS_CC); + DATE_CHECK_INITIALIZED(diobj1->initialized, DateInterval); + diobj2 = (php_interval_obj *) zend_object_store_get_object(zi2 TSRMLS_CC); + DATE_CHECK_INITIALIZED(diobj2->initialized, DateInterval); + + rtime = timelib_rel_add(diobj1->diff, diobj2->diff); + if (!rtime) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Relative interval cannot be used for interval addition"); + } + + php_date_instantiate(date_ce_interval, return_value TSRMLS_CC); + diobjr = zend_object_store_get_object(return_value TSRMLS_CC); + diobjr->diff = rtime; + diobjr->initialized = 1; +} +/* }}} */ + static int date_period_initialize(timelib_time **st, timelib_time **et, timelib_rel_time **d, long *recurrences, /*const*/ char *format, int format_length TSRMLS_DC) { timelib_time *b = NULL, *e = NULL; diff --git a/ext/date/php_date.h b/ext/date/php_date.h index 725590136c706..357a7ff1aaa7c 100644 --- a/ext/date/php_date.h +++ b/ext/date/php_date.h @@ -100,6 +100,7 @@ PHP_METHOD(DateInterval, __construct); PHP_METHOD(DateInterval, __wakeup); PHP_METHOD(DateInterval, __set_state); PHP_FUNCTION(date_interval_format); +PHP_FUNCTION(date_interval_add); PHP_FUNCTION(date_interval_create_from_date_string); PHP_METHOD(DatePeriod, __construct); From 0239991091cc50e72087a1882636bc28a81c650d Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 21 Jul 2013 16:35:38 +0100 Subject: [PATCH 2/6] Add test for DateInterval::add --- ext/date/tests/DateInterval_add_basic.phpt | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 ext/date/tests/DateInterval_add_basic.phpt diff --git a/ext/date/tests/DateInterval_add_basic.phpt b/ext/date/tests/DateInterval_add_basic.phpt new file mode 100644 index 0000000000000..c739555119b97 --- /dev/null +++ b/ext/date/tests/DateInterval_add_basic.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test DateInterval::add() basic functionality +--CREDITS-- +Jakub Zelenka +--SKIPIF-- + +--FILE-- +diff($date12); +echo $interval1->format('%Y-%M-%D %H:%i:%s') . "\n"; + +$date21 = new DateTime('2000-01-01 00:00:00'); +$date22 = new DateTime('2001-03-10 03:40:50'); +$interval2 = $date21->diff($date22); +echo $interval2->format('%Y-%M-%D %H:%i:%s') . "\n"; + +$interval = $interval1->add($interval2); +echo $interval->format('%Y-%M-%D %H:%i:%s') . "\n"; + +?> +--EXPECT-- +00-00-09 22:30:23 +01-02-09 03:40:50 +01-02-19 02:11:13 From 88824d475cf8e8dd9b4fa4a09cb252f2f441acad Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Thu, 25 Jul 2013 17:05:27 +0100 Subject: [PATCH 3/6] Add DateInterval::sub --- ext/date/lib/interval.c | 34 ++++++++++++++---- ext/date/lib/timelib.h | 1 + ext/date/lib/tm2unixtime.c | 3 +- ext/date/php_date.c | 40 +++++++++++++++++++--- ext/date/php_date.h | 1 + ext/date/tests/DateInterval_sub_basic.phpt | 28 +++++++++++++++ 6 files changed, 95 insertions(+), 12 deletions(-) create mode 100644 ext/date/tests/DateInterval_sub_basic.phpt diff --git a/ext/date/lib/interval.c b/ext/date/lib/interval.c index 8cf7f3e5e2cfd..d24b3550a7b3f 100644 --- a/ext/date/lib/interval.c +++ b/ext/date/lib/interval.c @@ -81,12 +81,34 @@ timelib_rel_time *timelib_rel_add(timelib_rel_time *one, timelib_rel_time *two) } rt = timelib_rel_time_ctor(); - rt->y = two->y + one->y; - rt->m = two->m + one->m; - rt->d = two->d + one->d; - rt->h = two->h + one->h; - rt->i = two->i + one->i; - rt->s = two->s + one->s; + rt->y = one->y + two->y; + rt->m = one->m + two->m; + rt->d = one->d + two->d; + rt->h = one->h + two->h; + rt->i = one->i + two->i; + rt->s = one->s + two->s; + + timelib_do_rel_normalize(NULL, rt); + + return rt; +} + +timelib_rel_time *timelib_rel_sub(timelib_rel_time *one, timelib_rel_time *two) +{ + timelib_rel_time *rt; + + if (one->have_weekday_relative || one->have_special_relative || + two->have_weekday_relative || two->have_special_relative) { + return NULL; + } + + rt = timelib_rel_time_ctor(); + rt->y = one->y - two->y; + rt->m = one->m - two->m; + rt->d = one->d - two->d; + rt->h = one->h - two->h; + rt->i = one->i - two->i; + rt->s = one->s - two->s; timelib_do_rel_normalize(NULL, rt); diff --git a/ext/date/lib/timelib.h b/ext/date/lib/timelib.h index e4341395ee0f3..ae2ffd4d46123 100644 --- a/ext/date/lib/timelib.h +++ b/ext/date/lib/timelib.h @@ -139,5 +139,6 @@ int timelib_astro_rise_set_altitude(timelib_time *time, double lon, double lat, /* from interval.c */ timelib_rel_time *timelib_diff(timelib_time *one, timelib_time *two); timelib_rel_time *timelib_rel_add(timelib_rel_time *one, timelib_rel_time *two); +timelib_rel_time *timelib_rel_sub(timelib_rel_time *one, timelib_rel_time *two); #endif diff --git a/ext/date/lib/tm2unixtime.c b/ext/date/lib/tm2unixtime.c index 8e9d7ee3d19ad..e2cb373a389ea 100644 --- a/ext/date/lib/tm2unixtime.c +++ b/ext/date/lib/tm2unixtime.c @@ -174,11 +174,10 @@ void timelib_do_rel_normalize(timelib_time *base, timelib_rel_time *rt) 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)); - if (base) { do_range_limit_days_relative(&base->y, &base->m, &rt->y, &rt->m, &rt->d, rt->invert); - do {} while (do_range_limit(0, 12, 12, &rt->m, &rt->y)); } + do {} while (do_range_limit(0, 12, 12, &rt->m, &rt->y)); } void timelib_do_normalize(timelib_time* time) diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 3f252e35a6743..12d62a4648a34 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -367,7 +367,7 @@ ZEND_BEGIN_ARG_INFO(arginfo_date_method_interval_format, 0) ZEND_ARG_INFO(0, format) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO(arginfo_date_method_interval_add, 0) +ZEND_BEGIN_ARG_INFO(arginfo_date_method_interval_addsub, 0) ZEND_ARG_INFO(0, interval) ZEND_END_ARG_INFO() @@ -381,7 +381,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_construct, 0, 0, 0) ZEND_ARG_INFO(0, interval_spec) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO(arginfo_date_interval_add, 0) +ZEND_BEGIN_ARG_INFO(arginfo_date_interval_addsub, 0) ZEND_ARG_INFO(0, interval1) ZEND_ARG_INFO(0, interval2) ZEND_END_ARG_INFO() @@ -441,7 +441,8 @@ const zend_function_entry date_functions[] = { PHP_FE(date_interval_create_from_date_string, arginfo_date_interval_create_from_date_string) PHP_FE(date_interval_format, arginfo_date_interval_format) - PHP_FE(date_interval_add, arginfo_date_interval_add) + PHP_FE(date_interval_add, arginfo_date_interval_addsub) + PHP_FE(date_interval_sub, arginfo_date_interval_addsub) /* Options and Configuration */ PHP_FE(date_default_timezone_set, arginfo_date_default_timezone_set) @@ -526,7 +527,8 @@ const zend_function_entry date_funcs_interval[] = { PHP_ME(DateInterval, __wakeup, NULL, ZEND_ACC_PUBLIC) PHP_ME(DateInterval, __set_state, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME_MAPPING(format, date_interval_format, arginfo_date_method_interval_format, 0) - PHP_ME_MAPPING(add, date_interval_add, arginfo_date_method_interval_add, 0) + PHP_ME_MAPPING(add, date_interval_add, arginfo_date_method_interval_addsub, 0) + PHP_ME_MAPPING(sub, date_interval_sub, arginfo_date_method_interval_addsub, 0) PHP_ME_MAPPING(createFromDateString, date_interval_create_from_date_string, arginfo_date_interval_create_from_date_string, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_FE_END }; @@ -4387,6 +4389,36 @@ PHP_FUNCTION(date_interval_add) } /* }}} */ +/* {{{ proto string date_interval_sub(DateInterval interval1, DateInterval interval2) + Add the intervals. +*/ +PHP_FUNCTION(date_interval_sub) +{ + zval *zi1, *zi2; + php_interval_obj *diobj1, *diobj2, *diobjr; + timelib_rel_time *rtime; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &zi1, date_ce_interval, &zi2, date_ce_interval) == FAILURE) { + RETURN_FALSE; + } + diobj1 = (php_interval_obj *) zend_object_store_get_object(zi1 TSRMLS_CC); + DATE_CHECK_INITIALIZED(diobj1->initialized, DateInterval); + diobj2 = (php_interval_obj *) zend_object_store_get_object(zi2 TSRMLS_CC); + DATE_CHECK_INITIALIZED(diobj2->initialized, DateInterval); + + rtime = timelib_rel_sub(diobj1->diff, diobj2->diff); + if (!rtime) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Relative interval cannot be used for interval substraction"); + } + + php_date_instantiate(date_ce_interval, return_value TSRMLS_CC); + diobjr = zend_object_store_get_object(return_value TSRMLS_CC); + diobjr->diff = rtime; + diobjr->initialized = 1; +} +/* }}} */ + + static int date_period_initialize(timelib_time **st, timelib_time **et, timelib_rel_time **d, long *recurrences, /*const*/ char *format, int format_length TSRMLS_DC) { timelib_time *b = NULL, *e = NULL; diff --git a/ext/date/php_date.h b/ext/date/php_date.h index 357a7ff1aaa7c..be72dd9f17740 100644 --- a/ext/date/php_date.h +++ b/ext/date/php_date.h @@ -101,6 +101,7 @@ PHP_METHOD(DateInterval, __wakeup); PHP_METHOD(DateInterval, __set_state); PHP_FUNCTION(date_interval_format); PHP_FUNCTION(date_interval_add); +PHP_FUNCTION(date_interval_sub); PHP_FUNCTION(date_interval_create_from_date_string); PHP_METHOD(DatePeriod, __construct); diff --git a/ext/date/tests/DateInterval_sub_basic.phpt b/ext/date/tests/DateInterval_sub_basic.phpt new file mode 100644 index 0000000000000..a25dfb17e0635 --- /dev/null +++ b/ext/date/tests/DateInterval_sub_basic.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test DateInterval::sub() basic functionality +--CREDITS-- +Jakub Zelenka +--SKIPIF-- + +--FILE-- +diff($date12); +echo $interval1->format('%Y-%M-%D %H:%i:%s') . "\n"; + +$date21 = new DateTime('2000-01-01 00:00:00'); +$date22 = new DateTime('2000-03-10 03:40:50'); +$interval2 = $date21->diff($date22); +echo $interval2->format('%Y-%M-%D %H:%i:%s') . "\n"; + +$interval = $interval1->sub($interval2); +echo $interval->format('%Y-%M-%D %H:%i:%s') . "\n"; + +?> +--EXPECT-- +01-00-09 22:30:23 +00-02-09 03:40:50 +00-10-00 18:49:33 From ce759885b89dc32112297e0de507d35e57d6f1d6 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 28 Jul 2013 14:15:28 +0100 Subject: [PATCH 4/6] Support DateInterval invert operation for add and sub --- ext/date/lib/interval.c | 64 +++++++++++++--------- ext/date/lib/timelib.h | 1 - ext/date/php_date.c | 4 +- ext/date/tests/DateInterval_add_basic.phpt | 5 ++ 4 files changed, 47 insertions(+), 27 deletions(-) diff --git a/ext/date/lib/interval.c b/ext/date/lib/interval.c index d24b3550a7b3f..87ab036e55359 100644 --- a/ext/date/lib/interval.c +++ b/ext/date/lib/interval.c @@ -71,9 +71,12 @@ timelib_rel_time *timelib_diff(timelib_time *one, timelib_time *two) return rt; } +#define timelib_rel_invert_member(rt, member) do { rt->member *= -1; rt->invert = !rt->invert; } while(0) + timelib_rel_time *timelib_rel_add(timelib_rel_time *one, timelib_rel_time *two) { timelib_rel_time *rt; + int one_mult, two_mult; if (one->have_weekday_relative || one->have_special_relative || two->have_weekday_relative || two->have_special_relative) { @@ -81,36 +84,47 @@ timelib_rel_time *timelib_rel_add(timelib_rel_time *one, timelib_rel_time *two) } rt = timelib_rel_time_ctor(); - rt->y = one->y + two->y; - rt->m = one->m + two->m; - rt->d = one->d + two->d; - rt->h = one->h + two->h; - rt->i = one->i + two->i; - rt->s = one->s + two->s; - - timelib_do_rel_normalize(NULL, rt); - - return rt; -} - -timelib_rel_time *timelib_rel_sub(timelib_rel_time *one, timelib_rel_time *two) -{ - timelib_rel_time *rt; - if (one->have_weekday_relative || one->have_special_relative || - two->have_weekday_relative || two->have_special_relative) { - return NULL; + if (one->invert && !two->invert) { + one_mult = two_mult = 1; + rt->invert = 1; + } else { + one_mult = one->invert ? -1 : 1; + two_mult = two->invert ? -1 : 1; } - + rt = timelib_rel_time_ctor(); - rt->y = one->y - two->y; - rt->m = one->m - two->m; - rt->d = one->d - two->d; - rt->h = one->h - two->h; - rt->i = one->i - two->i; - rt->s = one->s - two->s; + rt->y = one_mult * one->y + two_mult * two->y; + rt->m = one_mult * one->m + two_mult * two->m; + rt->d = one_mult * one->d + two_mult * two->d; + rt->h = one_mult * one->h + two_mult * two->h; + rt->i = one_mult * one->i + two_mult * two->i; + rt->s = one_mult * one->s + two_mult * two->s; timelib_do_rel_normalize(NULL, rt); + /* if the first not 0 rt member is negative, then invert */ + if (rt->y < 0) { + timelib_rel_invert_member(rt, y); + } else if (rt->y == 0) { + if (rt->m < 0) { + timelib_rel_invert_member(rt, m); + } else if (rt->m == 0) { + if (rt->d < 0) { + timelib_rel_invert_member(rt, d); + } else if (rt->d == 0) { + if (rt->h < 0) { + timelib_rel_invert_member(rt, h); + } else if (rt->h == 0) { + if (rt->i < 0) { + timelib_rel_invert_member(rt, i); + } else if (rt->i == 0 && rt->s < 0) { + timelib_rel_invert_member(rt, s); + } + } + } + } + } + return rt; } diff --git a/ext/date/lib/timelib.h b/ext/date/lib/timelib.h index ae2ffd4d46123..e4341395ee0f3 100644 --- a/ext/date/lib/timelib.h +++ b/ext/date/lib/timelib.h @@ -139,6 +139,5 @@ int timelib_astro_rise_set_altitude(timelib_time *time, double lon, double lat, /* from interval.c */ timelib_rel_time *timelib_diff(timelib_time *one, timelib_time *two); timelib_rel_time *timelib_rel_add(timelib_rel_time *one, timelib_rel_time *two); -timelib_rel_time *timelib_rel_sub(timelib_rel_time *one, timelib_rel_time *two); #endif diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 12d62a4648a34..932dbc2b27b14 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -4406,7 +4406,9 @@ PHP_FUNCTION(date_interval_sub) diobj2 = (php_interval_obj *) zend_object_store_get_object(zi2 TSRMLS_CC); DATE_CHECK_INITIALIZED(diobj2->initialized, DateInterval); - rtime = timelib_rel_sub(diobj1->diff, diobj2->diff); + diobj2->diff->invert = !diobj2->diff->invert; + rtime = timelib_rel_add(diobj1->diff, diobj2->diff); + diobj2->diff->invert = !diobj2->diff->invert; if (!rtime) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Relative interval cannot be used for interval substraction"); } diff --git a/ext/date/tests/DateInterval_add_basic.phpt b/ext/date/tests/DateInterval_add_basic.phpt index c739555119b97..8e48611474f4e 100644 --- a/ext/date/tests/DateInterval_add_basic.phpt +++ b/ext/date/tests/DateInterval_add_basic.phpt @@ -21,8 +21,13 @@ echo $interval2->format('%Y-%M-%D %H:%i:%s') . "\n"; $interval = $interval1->add($interval2); echo $interval->format('%Y-%M-%D %H:%i:%s') . "\n"; +$interval1->invert = 1; +$interval = $interval->add($interval1); +echo $interval->format('%Y-%M-%D %H:%i:%s') . "\n"; + ?> --EXPECT-- 00-00-09 22:30:23 01-02-09 03:40:50 01-02-19 02:11:13 +01-02-09 03:40:50 From c6288e044a70c621afe9058c006caece852560a8 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Thu, 1 Aug 2013 19:52:55 +0100 Subject: [PATCH 5/6] Fix invalid counting of inverted intervals when added or substracted --- ext/date/lib/interval.c | 7 ++-- ext/date/lib/timelib.h | 3 +- ext/date/lib/tm2unixtime.c | 31 +++++++++++++++--- ext/date/tests/DateInterval_add_basic.phpt | 37 ++++++++++++++++++++++ 4 files changed, 69 insertions(+), 9 deletions(-) diff --git a/ext/date/lib/interval.c b/ext/date/lib/interval.c index 87ab036e55359..cff1d74021768 100644 --- a/ext/date/lib/interval.c +++ b/ext/date/lib/interval.c @@ -62,7 +62,7 @@ timelib_rel_time *timelib_diff(timelib_time *one, timelib_time *two) rt->s = two->s - one->s; rt->days = abs(floor((one->sse - two->sse - (dst_h_corr * 3600) - (dst_m_corr * 60)) / 86400)); - timelib_do_rel_normalize(rt->invert ? one : two, rt); + timelib_do_rel_normalize_by_base(rt->invert ? one : two, rt); /* Restore old TZ info */ memcpy(one, &one_backup, sizeof(one_backup)); @@ -85,7 +85,7 @@ timelib_rel_time *timelib_rel_add(timelib_rel_time *one, timelib_rel_time *two) rt = timelib_rel_time_ctor(); - if (one->invert && !two->invert) { + if (one->invert && two->invert) { one_mult = two_mult = 1; rt->invert = 1; } else { @@ -93,7 +93,6 @@ timelib_rel_time *timelib_rel_add(timelib_rel_time *one, timelib_rel_time *two) two_mult = two->invert ? -1 : 1; } - rt = timelib_rel_time_ctor(); rt->y = one_mult * one->y + two_mult * two->y; rt->m = one_mult * one->m + two_mult * two->m; rt->d = one_mult * one->d + two_mult * two->d; @@ -101,7 +100,7 @@ timelib_rel_time *timelib_rel_add(timelib_rel_time *one, timelib_rel_time *two) rt->i = one_mult * one->i + two_mult * two->i; rt->s = one_mult * one->s + two_mult * two->s; - timelib_do_rel_normalize(NULL, rt); + timelib_do_rel_normalize(rt); /* if the first not 0 rt member is negative, then invert */ if (rt->y < 0) { diff --git a/ext/date/lib/timelib.h b/ext/date/lib/timelib.h index e4341395ee0f3..85121fad00203 100644 --- a/ext/date/lib/timelib.h +++ b/ext/date/lib/timelib.h @@ -85,7 +85,8 @@ void timelib_strtointerval(char *s, int len, /* From tm2unixtime.c */ void timelib_update_ts(timelib_time* time, timelib_tzinfo* tzi); void timelib_do_normalize(timelib_time *base); -void timelib_do_rel_normalize(timelib_time *base, timelib_rel_time *rt); +void timelib_do_rel_normalize_by_base(timelib_time *base, timelib_rel_time *rt); +void timelib_do_rel_normalize(timelib_rel_time *rt); /* From unixtime2tm.c */ int timelib_apply_localtime(timelib_time *t, unsigned int localtime); diff --git a/ext/date/lib/tm2unixtime.c b/ext/date/lib/tm2unixtime.c index e2cb373a389ea..33fc6d00717c3 100644 --- a/ext/date/lib/tm2unixtime.c +++ b/ext/date/lib/tm2unixtime.c @@ -168,18 +168,41 @@ static void do_adjust_for_weekday(timelib_time* time) time->relative.have_weekday_relative = 0; } -void timelib_do_rel_normalize(timelib_time *base, timelib_rel_time *rt) +void timelib_do_rel_normalize_by_base(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)); - if (base) { - do_range_limit_days_relative(&base->y, &base->m, &rt->y, &rt->m, &rt->d, rt->invert); - } + do_range_limit_days_relative(&base->y, &base->m, &rt->y, &rt->m, &rt->d, rt->invert); do {} while (do_range_limit(0, 12, 12, &rt->m, &rt->y)); } +void timelib_do_rel_normalize(timelib_rel_time *rt) +{ + int i, hmi; + timelib_sll *members[6] = {&rt->s, &rt->i, &rt->h, &rt->d, &rt->m, &rt->y}; + timelib_sll limits[6] = {60, 60, 24, 0, 12, 0}; + + for (i = 5; i >= 0; i--) { + if (*(members[i]) != 0) { + if (*(members[i]) < 0) { + *(members[i]) *= -1; + rt->invert = !rt->invert; + } + break; + } + } + /* save highest not zero member index */ + hmi = i + 1; + for (i = 0; i < 6; i++) { + if (i == hmi) + break; + if (limits[i]) + do {} while (do_range_limit(0, limits[i], limits[i], members[i], members[i+1])); + } +} + void timelib_do_normalize(timelib_time* time) { if (time->s != TIMELIB_UNSET) do {} while (do_range_limit(0, 60, 60, &time->s, &time->i)); diff --git a/ext/date/tests/DateInterval_add_basic.phpt b/ext/date/tests/DateInterval_add_basic.phpt index 8e48611474f4e..a5ff58da1103d 100644 --- a/ext/date/tests/DateInterval_add_basic.phpt +++ b/ext/date/tests/DateInterval_add_basic.phpt @@ -25,9 +25,46 @@ $interval1->invert = 1; $interval = $interval->add($interval1); echo $interval->format('%Y-%M-%D %H:%i:%s') . "\n"; +$i0 = new Dateinterval('P1Y4D'); +$i1 = new DateInterval('P1Y3D'); +$i0->invert = 1; + +$i2 = $i0->add($i1); /* -1 day */ +echo $i2->format('%y-%m-%d %h-%i-%s') . "\n"; +echo $i2->invert . "\n"; + +$i2 = $i0->sub($i1); /* -(2 years and 7 days) */ +echo $i2->format('%y-%m-%d %h-%i-%s') . "\n"; +echo $i2->invert . "\n"; + +$i0->invert = 0; +$i2 = $i0->sub($i1); +echo $i2->format('%y-%m-%d %h-%i-%s') . "\n"; +echo $i2->invert . "\n"; + +$i0 = new Dateinterval('P1Y4DT3H'); +$i1 = new DateInterval('P1Y4DT3H2M'); +$i2 = $i0->sub($i1); /* -2 minutes */ +echo $i2->format('%y-%m-%d %h-%i-%s') . "\n"; +echo $i2->invert . "\n"; + +$i2 = $i1->sub($i0); +echo $i2->format('%y-%m-%d %h-%i-%s') . "\n"; +echo $i2->invert . "\n"; + ?> --EXPECT-- 00-00-09 22:30:23 01-02-09 03:40:50 01-02-19 02:11:13 01-02-09 03:40:50 +0-0-1 0-0-0 +1 +2-0-7 0-0-0 +1 +0-0-1 0-0-0 +0 +0-0-0 0-2-0 +1 +0-0-0 0-2-0 +0 From 9d1e4857578a349af072806137abba8d609c1c5f Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Wed, 14 Aug 2013 18:52:29 +0100 Subject: [PATCH 6/6] Remove useless normalization that is already done in timelib_do_rel_normalize --- ext/date/lib/interval.c | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/ext/date/lib/interval.c b/ext/date/lib/interval.c index cff1d74021768..909009d41d745 100644 --- a/ext/date/lib/interval.c +++ b/ext/date/lib/interval.c @@ -102,28 +102,5 @@ timelib_rel_time *timelib_rel_add(timelib_rel_time *one, timelib_rel_time *two) timelib_do_rel_normalize(rt); - /* if the first not 0 rt member is negative, then invert */ - if (rt->y < 0) { - timelib_rel_invert_member(rt, y); - } else if (rt->y == 0) { - if (rt->m < 0) { - timelib_rel_invert_member(rt, m); - } else if (rt->m == 0) { - if (rt->d < 0) { - timelib_rel_invert_member(rt, d); - } else if (rt->d == 0) { - if (rt->h < 0) { - timelib_rel_invert_member(rt, h); - } else if (rt->h == 0) { - if (rt->i < 0) { - timelib_rel_invert_member(rt, i); - } else if (rt->i == 0 && rt->s < 0) { - timelib_rel_invert_member(rt, s); - } - } - } - } - } - return rt; }