diff --git a/ext/date/config.w32 b/ext/date/config.w32 index 78cca036d380..327242f128ac 100644 --- a/ext/date/config.w32 +++ b/ext/date/config.w32 @@ -1,6 +1,6 @@ // vim:ft=javascript -EXTENSION("date", "php_date.c", false, "/Iext/date/lib /DHAVE_TIMELIB_CONFIG_H=1"); +EXTENSION("date", "php_date.c php_time.c time_duration.c", false, "/Iext/date/lib /DHAVE_TIMELIB_CONFIG_H=1"); PHP_DATE = "yes"; ADD_SOURCES("ext/date/lib", "astro.c timelib.c dow.c duration.c parse_date.c parse_posix.c parse_tz.c tm2unixtime.c unixtime2tm.c parse_iso_intervals.c interval.c", "date"); diff --git a/ext/date/config0.m4 b/ext/date/config0.m4 index 4853882465e0..aab6d3d139b3 100644 --- a/ext/date/config0.m4 +++ b/ext/date/config0.m4 @@ -18,7 +18,7 @@ timelib_sources="lib/astro.c lib/dow.c lib/duration.c lib/parse_date.c lib/parse lib/timelib.c lib/tm2unixtime.c lib/unixtime2tm.c lib/parse_iso_intervals.c lib/interval.c" PHP_NEW_EXTENSION([date], - [php_date.c], + [php_date.c php_time.c time_duration.c], [no],, [$PHP_DATE_CFLAGS]) diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 0e24e4450641..9f9f0a6159ed 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -18,6 +18,7 @@ #include "ext/standard/info.h" #include "ext/standard/php_versioning.h" #include "php_date.h" +#include "php_time.h" #include "zend_attributes.h" #include "zend_interfaces.h" #include "zend_exceptions.h" @@ -386,6 +387,7 @@ static PHP_GINIT_FUNCTION(date) date_globals->default_timezone = NULL; date_globals->timezone = NULL; date_globals->tzcache = NULL; + date_globals->duration_cache = NULL; } /* }}} */ @@ -418,6 +420,10 @@ PHP_RSHUTDOWN_FUNCTION(date) efree(DATEG(timezone)); } DATEG(timezone) = NULL; + if (DATEG(duration_cache)) { + zend_object_release(DATEG(duration_cache)); + } + DATEG(duration_cache) = NULL; return SUCCESS; } @@ -447,6 +453,7 @@ PHP_MINIT_FUNCTION(date) REGISTER_INI_ENTRIES(); date_register_classes(); register_php_date_symbols(module_number); + PHP_MINIT(date_time)(INIT_FUNC_ARGS_PASSTHRU); php_date_global_timezone_db = NULL; php_date_global_timezone_db_enabled = 0; diff --git a/ext/date/php_date.h b/ext/date/php_date.h index 651cc28225fd..97a49974f1a4 100644 --- a/ext/date/php_date.h +++ b/ext/date/php_date.h @@ -115,8 +115,11 @@ ZEND_BEGIN_MODULE_GLOBALS(date) char *timezone; HashTable *tzcache; timelib_error_container *last_errors; + zend_object *duration_cache; ZEND_END_MODULE_GLOBALS(date) +PHPAPI ZEND_EXTERN_MODULE_GLOBALS(date) + #define DATEG(v) ZEND_MODULE_GLOBALS_ACCESSOR(date, v) PHPAPI time_t php_time(void); diff --git a/ext/date/php_time.c b/ext/date/php_time.c new file mode 100644 index 000000000000..2c3698f63fbd --- /dev/null +++ b/ext/date/php_time.c @@ -0,0 +1,65 @@ +/* + +----------------------------------------------------------------------+ + | Copyright © The PHP Group and Contributors. | + +----------------------------------------------------------------------+ + | This source file is subject to the Modified BSD License that is | + | bundled with this package in the file LICENSE, and is available | + | through the World Wide Web at . | + | | + | SPDX-License-Identifier: BSD-3-Clause | + +----------------------------------------------------------------------+ + | Authors: Derick Rethans | + | Tim Düsterhus | + +----------------------------------------------------------------------+ + */ + +#include "php.h" +#include "Zend/zend_exceptions.h" + +#include "php_time.h" +#include "time_arginfo.h" + +zend_class_entry *php_date_ce_time_duration; +zend_class_entry *php_date_ce_time_timeexception; + +static zend_object_handlers time_duration_object_handlers; + +static zend_object *time_duration_object_create(zend_class_entry *ce) +{ + php_date_time_duration *obj = zend_object_alloc(sizeof(*obj), ce); + + zend_object_std_init(&obj->std, ce); + object_properties_init(&obj->std, ce); + + timelib_duration_ctor_static(&obj->duration, /* seconds */ 0, /* nanoseconds */ 0, /* negative */ false); + + return &obj->std; +} + +static zend_object *time_duration_object_clone(zend_object *object) +{ + const php_date_time_duration *obj = php_date_time_duration_from_obj(object); + + php_date_time_duration *new_obj = php_date_time_duration_from_obj(object->ce->create_object(object->ce)); + + new_obj->duration = obj->duration; + zend_objects_clone_members(&new_obj->std, &obj->std); + + return &new_obj->std; +} + +PHP_MINIT_FUNCTION(date_time) +{ + /* Time\TimeException */ + php_date_ce_time_timeexception = register_class_Time_TimeException(zend_ce_exception); + + /* Time\Duration */ + memcpy(&time_duration_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + time_duration_object_handlers.offset = offsetof(php_date_time_duration, std); + time_duration_object_handlers.clone_obj = time_duration_object_clone; + php_date_ce_time_duration = register_class_Time_Duration(); + php_date_ce_time_duration->create_object = time_duration_object_create; + php_date_ce_time_duration->default_object_handlers = &time_duration_object_handlers; + + return SUCCESS; +} diff --git a/ext/date/php_time.h b/ext/date/php_time.h new file mode 100644 index 000000000000..fad711b519e7 --- /dev/null +++ b/ext/date/php_time.h @@ -0,0 +1,48 @@ +/* + +----------------------------------------------------------------------+ + | Copyright © The PHP Group and Contributors. | + +----------------------------------------------------------------------+ + | This source file is subject to the Modified BSD License that is | + | bundled with this package in the file LICENSE, and is available | + | through the World Wide Web at . | + | | + | SPDX-License-Identifier: BSD-3-Clause | + +----------------------------------------------------------------------+ + | Authors: Derick Rethans | + | Tim Düsterhus | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHP_DATE_TIME_H +# define PHP_DATE_TIME_H + +# include "php.h" +# include "lib/timelib.h" + +typedef struct php_date_time_duration { + timelib_duration duration; + zend_object std; +} php_date_time_duration; + +# define php_date_time_duration_from_obj(obj) ZEND_CONTAINER_OF(obj, php_date_time_duration, std) + +# define Z_DATE_TIME_DURATION_P(zv) php_date_time_duration_from_obj(Z_OBJ_P((zv))) + +# define Z_PARAM_DATE_TIME_DURATION(d) do { \ + zend_object *__d; \ + Z_PARAM_OBJ_OF_CLASS(__d, php_date_ce_time_duration); \ + d = php_date_time_duration_from_obj(__d); \ + } while (0); + +# define Z_PARAM_DATE_TIME_DURATION_OR_NULL(d) do { \ + zend_object *__d; \ + Z_PARAM_OBJ_OF_CLASS_OR_NULL(__d, php_date_ce_time_duration); \ + d = __d ? php_date_time_duration_from_obj(__d) : NULL; \ + } while (0); + +PHPAPI extern zend_class_entry *php_date_ce_time_duration; +PHPAPI extern zend_class_entry *php_date_ce_time_timeexception; + +PHP_MINIT_FUNCTION(date_time); + +#endif /* PHP_DATE_TIME_H */ diff --git a/ext/date/tests/time/duration/clone.phpt b/ext/date/tests/time/duration/clone.phpt new file mode 100644 index 000000000000..06ad23dfe633 --- /dev/null +++ b/ext/date/tests/time/duration/clone.phpt @@ -0,0 +1,24 @@ +--TEST-- +Time\Duration: clone +--FILE-- +negate()), PHP_EOL; +echo fc(Time\Duration::fromSeconds(1, 1)->negate()), PHP_EOL; + +?> +--EXPECT-- + +0.000000000 + +0.000000001 + +1.000000001 + -0.000000001 + -1.000000001 diff --git a/ext/date/tests/time/duration/helper.inc b/ext/date/tests/time/duration/helper.inc new file mode 100644 index 000000000000..a961315b179b --- /dev/null +++ b/ext/date/tests/time/duration/helper.inc @@ -0,0 +1,31 @@ +negative ? "-" : ($plus_sign ? "+" : " ")), $d->seconds, $d->nanoseconds); + if ($pad) { + $result = str_pad($result, 21, pad_type: STR_PAD_LEFT); + } + + return $result; +} + +function as_int(Time\Duration $d): int { + return ($d->negative ? -1 : 1) * ($d->seconds * 1_000_000_000 + $d->nanoseconds); +} + +function negate(Time\Duration $d): Time\Duration { + return $d->negate(); +} + +function is_negative(Time\Duration $d): bool { + return $d->negative; +} + +/** @return Time\Duration[] */ +function negate_all( + array $d /** @param Time\Duration[] */, +): array { + return $d + |> array_map(negate(?), ?) + |> array_filter(?, is_negative(?)); +} diff --git a/ext/date/tests/time/duration/methods/absolute.phpt b/ext/date/tests/time/duration/methods/absolute.phpt new file mode 100644 index 000000000000..86578488ae89 --- /dev/null +++ b/ext/date/tests/time/duration/methods/absolute.phpt @@ -0,0 +1,29 @@ +--TEST-- +Time\Duration::absolute() +--FILE-- +absolute()), PHP_EOL; +echo f(Time\Duration::fromSeconds(0, 0)->negate()->absolute()), PHP_EOL; + +echo f(Time\Duration::fromSeconds(1, 0)->absolute()), PHP_EOL; +echo f(Time\Duration::fromSeconds(1, 0)->negate()->absolute()), PHP_EOL; + +echo f(Time\Duration::fromSeconds(0, 1)->absolute()), PHP_EOL; +echo f(Time\Duration::fromSeconds(0, 1)->negate()->absolute()), PHP_EOL; + +echo f(Time\Duration::fromSeconds(1, 1)->absolute()), PHP_EOL; +echo f(Time\Duration::fromSeconds(1, 1)->negate()->absolute()), PHP_EOL; + +?> +--EXPECT-- + +0.000000000 + +0.000000000 + +1.000000000 + +1.000000000 + +0.000000001 + +0.000000001 + +1.000000001 + +1.000000001 diff --git a/ext/date/tests/time/duration/methods/add.phpt b/ext/date/tests/time/duration/methods/add.phpt new file mode 100644 index 000000000000..825bd45de2fe --- /dev/null +++ b/ext/date/tests/time/duration/methods/add.phpt @@ -0,0 +1,371 @@ +--TEST-- +Time\Duration::add() +--FILE-- +add($b); + echo f($a, pad: false, plus_sign: false), " + ", f($b, pad: false, plus_sign: false), " = ", f($result, pad: false), PHP_EOL; + if (PHP_INT_SIZE != 4 && (as_int($a) + as_int($b) !== as_int($result))) { + throw new \Exception('Verification failed'); + } + } +} + +?> +--EXPECT-- +======== + 0.000000000 + 0.000000000 = +0.000000000 + 0.000000000 + 0.000000001 = +0.000000001 + 0.000000000 + 0.000000002 = +0.000000002 + 0.000000000 + 1.000000000 = +1.000000000 + 0.000000000 + 1.000000001 = +1.000000001 + 0.000000000 + 1.000000002 = +1.000000002 + 0.000000000 + 2.000000000 = +2.000000000 + 0.000000000 + 2.000000001 = +2.000000001 + 0.000000000 + 2.000000002 = +2.000000002 +==== + 0.000000000 + -0.000000001 = -0.000000001 + 0.000000000 + -0.000000002 = -0.000000002 + 0.000000000 + -1.000000000 = -1.000000000 + 0.000000000 + -1.000000001 = -1.000000001 + 0.000000000 + -1.000000002 = -1.000000002 + 0.000000000 + -2.000000000 = -2.000000000 + 0.000000000 + -2.000000001 = -2.000000001 + 0.000000000 + -2.000000002 = -2.000000002 +======== + 0.000000001 + 0.000000000 = +0.000000001 + 0.000000001 + 0.000000001 = +0.000000002 + 0.000000001 + 0.000000002 = +0.000000003 + 0.000000001 + 1.000000000 = +1.000000001 + 0.000000001 + 1.000000001 = +1.000000002 + 0.000000001 + 1.000000002 = +1.000000003 + 0.000000001 + 2.000000000 = +2.000000001 + 0.000000001 + 2.000000001 = +2.000000002 + 0.000000001 + 2.000000002 = +2.000000003 +==== + 0.000000001 + -0.000000001 = +0.000000000 + 0.000000001 + -0.000000002 = -0.000000001 + 0.000000001 + -1.000000000 = -0.999999999 + 0.000000001 + -1.000000001 = -1.000000000 + 0.000000001 + -1.000000002 = -1.000000001 + 0.000000001 + -2.000000000 = -1.999999999 + 0.000000001 + -2.000000001 = -2.000000000 + 0.000000001 + -2.000000002 = -2.000000001 +======== + 0.000000002 + 0.000000000 = +0.000000002 + 0.000000002 + 0.000000001 = +0.000000003 + 0.000000002 + 0.000000002 = +0.000000004 + 0.000000002 + 1.000000000 = +1.000000002 + 0.000000002 + 1.000000001 = +1.000000003 + 0.000000002 + 1.000000002 = +1.000000004 + 0.000000002 + 2.000000000 = +2.000000002 + 0.000000002 + 2.000000001 = +2.000000003 + 0.000000002 + 2.000000002 = +2.000000004 +==== + 0.000000002 + -0.000000001 = +0.000000001 + 0.000000002 + -0.000000002 = +0.000000000 + 0.000000002 + -1.000000000 = -0.999999998 + 0.000000002 + -1.000000001 = -0.999999999 + 0.000000002 + -1.000000002 = -1.000000000 + 0.000000002 + -2.000000000 = -1.999999998 + 0.000000002 + -2.000000001 = -1.999999999 + 0.000000002 + -2.000000002 = -2.000000000 +======== + 1.000000000 + 0.000000000 = +1.000000000 + 1.000000000 + 0.000000001 = +1.000000001 + 1.000000000 + 0.000000002 = +1.000000002 + 1.000000000 + 1.000000000 = +2.000000000 + 1.000000000 + 1.000000001 = +2.000000001 + 1.000000000 + 1.000000002 = +2.000000002 + 1.000000000 + 2.000000000 = +3.000000000 + 1.000000000 + 2.000000001 = +3.000000001 + 1.000000000 + 2.000000002 = +3.000000002 +==== + 1.000000000 + -0.000000001 = +0.999999999 + 1.000000000 + -0.000000002 = +0.999999998 + 1.000000000 + -1.000000000 = +0.000000000 + 1.000000000 + -1.000000001 = -0.000000001 + 1.000000000 + -1.000000002 = -0.000000002 + 1.000000000 + -2.000000000 = -1.000000000 + 1.000000000 + -2.000000001 = -1.000000001 + 1.000000000 + -2.000000002 = -1.000000002 +======== + 1.000000001 + 0.000000000 = +1.000000001 + 1.000000001 + 0.000000001 = +1.000000002 + 1.000000001 + 0.000000002 = +1.000000003 + 1.000000001 + 1.000000000 = +2.000000001 + 1.000000001 + 1.000000001 = +2.000000002 + 1.000000001 + 1.000000002 = +2.000000003 + 1.000000001 + 2.000000000 = +3.000000001 + 1.000000001 + 2.000000001 = +3.000000002 + 1.000000001 + 2.000000002 = +3.000000003 +==== + 1.000000001 + -0.000000001 = +1.000000000 + 1.000000001 + -0.000000002 = +0.999999999 + 1.000000001 + -1.000000000 = +0.000000001 + 1.000000001 + -1.000000001 = +0.000000000 + 1.000000001 + -1.000000002 = -0.000000001 + 1.000000001 + -2.000000000 = -0.999999999 + 1.000000001 + -2.000000001 = -1.000000000 + 1.000000001 + -2.000000002 = -1.000000001 +======== + 1.000000002 + 0.000000000 = +1.000000002 + 1.000000002 + 0.000000001 = +1.000000003 + 1.000000002 + 0.000000002 = +1.000000004 + 1.000000002 + 1.000000000 = +2.000000002 + 1.000000002 + 1.000000001 = +2.000000003 + 1.000000002 + 1.000000002 = +2.000000004 + 1.000000002 + 2.000000000 = +3.000000002 + 1.000000002 + 2.000000001 = +3.000000003 + 1.000000002 + 2.000000002 = +3.000000004 +==== + 1.000000002 + -0.000000001 = +1.000000001 + 1.000000002 + -0.000000002 = +1.000000000 + 1.000000002 + -1.000000000 = +0.000000002 + 1.000000002 + -1.000000001 = +0.000000001 + 1.000000002 + -1.000000002 = +0.000000000 + 1.000000002 + -2.000000000 = -0.999999998 + 1.000000002 + -2.000000001 = -0.999999999 + 1.000000002 + -2.000000002 = -1.000000000 +======== + 2.000000000 + 0.000000000 = +2.000000000 + 2.000000000 + 0.000000001 = +2.000000001 + 2.000000000 + 0.000000002 = +2.000000002 + 2.000000000 + 1.000000000 = +3.000000000 + 2.000000000 + 1.000000001 = +3.000000001 + 2.000000000 + 1.000000002 = +3.000000002 + 2.000000000 + 2.000000000 = +4.000000000 + 2.000000000 + 2.000000001 = +4.000000001 + 2.000000000 + 2.000000002 = +4.000000002 +==== + 2.000000000 + -0.000000001 = +1.999999999 + 2.000000000 + -0.000000002 = +1.999999998 + 2.000000000 + -1.000000000 = +1.000000000 + 2.000000000 + -1.000000001 = +0.999999999 + 2.000000000 + -1.000000002 = +0.999999998 + 2.000000000 + -2.000000000 = +0.000000000 + 2.000000000 + -2.000000001 = -0.000000001 + 2.000000000 + -2.000000002 = -0.000000002 +======== + 2.000000001 + 0.000000000 = +2.000000001 + 2.000000001 + 0.000000001 = +2.000000002 + 2.000000001 + 0.000000002 = +2.000000003 + 2.000000001 + 1.000000000 = +3.000000001 + 2.000000001 + 1.000000001 = +3.000000002 + 2.000000001 + 1.000000002 = +3.000000003 + 2.000000001 + 2.000000000 = +4.000000001 + 2.000000001 + 2.000000001 = +4.000000002 + 2.000000001 + 2.000000002 = +4.000000003 +==== + 2.000000001 + -0.000000001 = +2.000000000 + 2.000000001 + -0.000000002 = +1.999999999 + 2.000000001 + -1.000000000 = +1.000000001 + 2.000000001 + -1.000000001 = +1.000000000 + 2.000000001 + -1.000000002 = +0.999999999 + 2.000000001 + -2.000000000 = +0.000000001 + 2.000000001 + -2.000000001 = +0.000000000 + 2.000000001 + -2.000000002 = -0.000000001 +======== + 2.000000002 + 0.000000000 = +2.000000002 + 2.000000002 + 0.000000001 = +2.000000003 + 2.000000002 + 0.000000002 = +2.000000004 + 2.000000002 + 1.000000000 = +3.000000002 + 2.000000002 + 1.000000001 = +3.000000003 + 2.000000002 + 1.000000002 = +3.000000004 + 2.000000002 + 2.000000000 = +4.000000002 + 2.000000002 + 2.000000001 = +4.000000003 + 2.000000002 + 2.000000002 = +4.000000004 +==== + 2.000000002 + -0.000000001 = +2.000000001 + 2.000000002 + -0.000000002 = +2.000000000 + 2.000000002 + -1.000000000 = +1.000000002 + 2.000000002 + -1.000000001 = +1.000000001 + 2.000000002 + -1.000000002 = +1.000000000 + 2.000000002 + -2.000000000 = +0.000000002 + 2.000000002 + -2.000000001 = +0.000000001 + 2.000000002 + -2.000000002 = +0.000000000 +======== +-0.000000001 + 0.000000000 = -0.000000001 +-0.000000001 + 0.000000001 = +0.000000000 +-0.000000001 + 0.000000002 = +0.000000001 +-0.000000001 + 1.000000000 = +0.999999999 +-0.000000001 + 1.000000001 = +1.000000000 +-0.000000001 + 1.000000002 = +1.000000001 +-0.000000001 + 2.000000000 = +1.999999999 +-0.000000001 + 2.000000001 = +2.000000000 +-0.000000001 + 2.000000002 = +2.000000001 +==== +-0.000000001 + -0.000000001 = -0.000000002 +-0.000000001 + -0.000000002 = -0.000000003 +-0.000000001 + -1.000000000 = -1.000000001 +-0.000000001 + -1.000000001 = -1.000000002 +-0.000000001 + -1.000000002 = -1.000000003 +-0.000000001 + -2.000000000 = -2.000000001 +-0.000000001 + -2.000000001 = -2.000000002 +-0.000000001 + -2.000000002 = -2.000000003 +======== +-0.000000002 + 0.000000000 = -0.000000002 +-0.000000002 + 0.000000001 = -0.000000001 +-0.000000002 + 0.000000002 = +0.000000000 +-0.000000002 + 1.000000000 = +0.999999998 +-0.000000002 + 1.000000001 = +0.999999999 +-0.000000002 + 1.000000002 = +1.000000000 +-0.000000002 + 2.000000000 = +1.999999998 +-0.000000002 + 2.000000001 = +1.999999999 +-0.000000002 + 2.000000002 = +2.000000000 +==== +-0.000000002 + -0.000000001 = -0.000000003 +-0.000000002 + -0.000000002 = -0.000000004 +-0.000000002 + -1.000000000 = -1.000000002 +-0.000000002 + -1.000000001 = -1.000000003 +-0.000000002 + -1.000000002 = -1.000000004 +-0.000000002 + -2.000000000 = -2.000000002 +-0.000000002 + -2.000000001 = -2.000000003 +-0.000000002 + -2.000000002 = -2.000000004 +======== +-1.000000000 + 0.000000000 = -1.000000000 +-1.000000000 + 0.000000001 = -0.999999999 +-1.000000000 + 0.000000002 = -0.999999998 +-1.000000000 + 1.000000000 = +0.000000000 +-1.000000000 + 1.000000001 = +0.000000001 +-1.000000000 + 1.000000002 = +0.000000002 +-1.000000000 + 2.000000000 = +1.000000000 +-1.000000000 + 2.000000001 = +1.000000001 +-1.000000000 + 2.000000002 = +1.000000002 +==== +-1.000000000 + -0.000000001 = -1.000000001 +-1.000000000 + -0.000000002 = -1.000000002 +-1.000000000 + -1.000000000 = -2.000000000 +-1.000000000 + -1.000000001 = -2.000000001 +-1.000000000 + -1.000000002 = -2.000000002 +-1.000000000 + -2.000000000 = -3.000000000 +-1.000000000 + -2.000000001 = -3.000000001 +-1.000000000 + -2.000000002 = -3.000000002 +======== +-1.000000001 + 0.000000000 = -1.000000001 +-1.000000001 + 0.000000001 = -1.000000000 +-1.000000001 + 0.000000002 = -0.999999999 +-1.000000001 + 1.000000000 = -0.000000001 +-1.000000001 + 1.000000001 = +0.000000000 +-1.000000001 + 1.000000002 = +0.000000001 +-1.000000001 + 2.000000000 = +0.999999999 +-1.000000001 + 2.000000001 = +1.000000000 +-1.000000001 + 2.000000002 = +1.000000001 +==== +-1.000000001 + -0.000000001 = -1.000000002 +-1.000000001 + -0.000000002 = -1.000000003 +-1.000000001 + -1.000000000 = -2.000000001 +-1.000000001 + -1.000000001 = -2.000000002 +-1.000000001 + -1.000000002 = -2.000000003 +-1.000000001 + -2.000000000 = -3.000000001 +-1.000000001 + -2.000000001 = -3.000000002 +-1.000000001 + -2.000000002 = -3.000000003 +======== +-1.000000002 + 0.000000000 = -1.000000002 +-1.000000002 + 0.000000001 = -1.000000001 +-1.000000002 + 0.000000002 = -1.000000000 +-1.000000002 + 1.000000000 = -0.000000002 +-1.000000002 + 1.000000001 = -0.000000001 +-1.000000002 + 1.000000002 = +0.000000000 +-1.000000002 + 2.000000000 = +0.999999998 +-1.000000002 + 2.000000001 = +0.999999999 +-1.000000002 + 2.000000002 = +1.000000000 +==== +-1.000000002 + -0.000000001 = -1.000000003 +-1.000000002 + -0.000000002 = -1.000000004 +-1.000000002 + -1.000000000 = -2.000000002 +-1.000000002 + -1.000000001 = -2.000000003 +-1.000000002 + -1.000000002 = -2.000000004 +-1.000000002 + -2.000000000 = -3.000000002 +-1.000000002 + -2.000000001 = -3.000000003 +-1.000000002 + -2.000000002 = -3.000000004 +======== +-2.000000000 + 0.000000000 = -2.000000000 +-2.000000000 + 0.000000001 = -1.999999999 +-2.000000000 + 0.000000002 = -1.999999998 +-2.000000000 + 1.000000000 = -1.000000000 +-2.000000000 + 1.000000001 = -0.999999999 +-2.000000000 + 1.000000002 = -0.999999998 +-2.000000000 + 2.000000000 = +0.000000000 +-2.000000000 + 2.000000001 = +0.000000001 +-2.000000000 + 2.000000002 = +0.000000002 +==== +-2.000000000 + -0.000000001 = -2.000000001 +-2.000000000 + -0.000000002 = -2.000000002 +-2.000000000 + -1.000000000 = -3.000000000 +-2.000000000 + -1.000000001 = -3.000000001 +-2.000000000 + -1.000000002 = -3.000000002 +-2.000000000 + -2.000000000 = -4.000000000 +-2.000000000 + -2.000000001 = -4.000000001 +-2.000000000 + -2.000000002 = -4.000000002 +======== +-2.000000001 + 0.000000000 = -2.000000001 +-2.000000001 + 0.000000001 = -2.000000000 +-2.000000001 + 0.000000002 = -1.999999999 +-2.000000001 + 1.000000000 = -1.000000001 +-2.000000001 + 1.000000001 = -1.000000000 +-2.000000001 + 1.000000002 = -0.999999999 +-2.000000001 + 2.000000000 = -0.000000001 +-2.000000001 + 2.000000001 = +0.000000000 +-2.000000001 + 2.000000002 = +0.000000001 +==== +-2.000000001 + -0.000000001 = -2.000000002 +-2.000000001 + -0.000000002 = -2.000000003 +-2.000000001 + -1.000000000 = -3.000000001 +-2.000000001 + -1.000000001 = -3.000000002 +-2.000000001 + -1.000000002 = -3.000000003 +-2.000000001 + -2.000000000 = -4.000000001 +-2.000000001 + -2.000000001 = -4.000000002 +-2.000000001 + -2.000000002 = -4.000000003 +======== +-2.000000002 + 0.000000000 = -2.000000002 +-2.000000002 + 0.000000001 = -2.000000001 +-2.000000002 + 0.000000002 = -2.000000000 +-2.000000002 + 1.000000000 = -1.000000002 +-2.000000002 + 1.000000001 = -1.000000001 +-2.000000002 + 1.000000002 = -1.000000000 +-2.000000002 + 2.000000000 = -0.000000002 +-2.000000002 + 2.000000001 = -0.000000001 +-2.000000002 + 2.000000002 = +0.000000000 +==== +-2.000000002 + -0.000000001 = -2.000000003 +-2.000000002 + -0.000000002 = -2.000000004 +-2.000000002 + -1.000000000 = -3.000000002 +-2.000000002 + -1.000000001 = -3.000000003 +-2.000000002 + -1.000000002 = -3.000000004 +-2.000000002 + -2.000000000 = -4.000000002 +-2.000000002 + -2.000000001 = -4.000000003 +-2.000000002 + -2.000000002 = -4.000000004 diff --git a/ext/date/tests/time/duration/methods/add_32.phpt b/ext/date/tests/time/duration/methods/add_32.phpt new file mode 100644 index 000000000000..f436d0a63ffa --- /dev/null +++ b/ext/date/tests/time/duration/methods/add_32.phpt @@ -0,0 +1,23 @@ +--TEST-- +Time\Duration::add() (32 bit variation) +--SKIPIF-- + +--FILE-- +add($b); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Time\TimeException: The maximum representable range is 2_147_483_647 seconds (roughly 68 years) diff --git a/ext/date/tests/time/duration/methods/add_64.phpt b/ext/date/tests/time/duration/methods/add_64.phpt new file mode 100644 index 000000000000..98448409bf19 --- /dev/null +++ b/ext/date/tests/time/duration/methods/add_64.phpt @@ -0,0 +1,23 @@ +--TEST-- +Time\Duration::add() (64 bit variation) +--SKIPIF-- + +--FILE-- +add($b); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Time\TimeException: The maximum representable range is 9_223_372_035 seconds (roughly 292 years) diff --git a/ext/date/tests/time/duration/methods/compare.phpt b/ext/date/tests/time/duration/methods/compare.phpt new file mode 100644 index 000000000000..488a39c2fc16 --- /dev/null +++ b/ext/date/tests/time/duration/methods/compare.phpt @@ -0,0 +1,369 @@ +--TEST-- +Time\Duration::absolute() +--FILE-- +')), " ", f($b, pad: false), PHP_EOL; + } +} + +?> +--EXPECT-- +======== ++0.000000000 = +0.000000000 ++0.000000000 < +0.000000001 ++0.000000000 < +0.000000002 ++0.000000000 < +1.000000000 ++0.000000000 < +1.000000001 ++0.000000000 < +1.000000002 ++0.000000000 < +2.000000000 ++0.000000000 < +2.000000001 ++0.000000000 < +2.000000002 +==== ++0.000000000 > -0.000000001 ++0.000000000 > -0.000000002 ++0.000000000 > -1.000000000 ++0.000000000 > -1.000000001 ++0.000000000 > -1.000000002 ++0.000000000 > -2.000000000 ++0.000000000 > -2.000000001 ++0.000000000 > -2.000000002 +======== ++0.000000001 > +0.000000000 ++0.000000001 = +0.000000001 ++0.000000001 < +0.000000002 ++0.000000001 < +1.000000000 ++0.000000001 < +1.000000001 ++0.000000001 < +1.000000002 ++0.000000001 < +2.000000000 ++0.000000001 < +2.000000001 ++0.000000001 < +2.000000002 +==== ++0.000000001 > -0.000000001 ++0.000000001 > -0.000000002 ++0.000000001 > -1.000000000 ++0.000000001 > -1.000000001 ++0.000000001 > -1.000000002 ++0.000000001 > -2.000000000 ++0.000000001 > -2.000000001 ++0.000000001 > -2.000000002 +======== ++0.000000002 > +0.000000000 ++0.000000002 > +0.000000001 ++0.000000002 = +0.000000002 ++0.000000002 < +1.000000000 ++0.000000002 < +1.000000001 ++0.000000002 < +1.000000002 ++0.000000002 < +2.000000000 ++0.000000002 < +2.000000001 ++0.000000002 < +2.000000002 +==== ++0.000000002 > -0.000000001 ++0.000000002 > -0.000000002 ++0.000000002 > -1.000000000 ++0.000000002 > -1.000000001 ++0.000000002 > -1.000000002 ++0.000000002 > -2.000000000 ++0.000000002 > -2.000000001 ++0.000000002 > -2.000000002 +======== ++1.000000000 > +0.000000000 ++1.000000000 > +0.000000001 ++1.000000000 > +0.000000002 ++1.000000000 = +1.000000000 ++1.000000000 < +1.000000001 ++1.000000000 < +1.000000002 ++1.000000000 < +2.000000000 ++1.000000000 < +2.000000001 ++1.000000000 < +2.000000002 +==== ++1.000000000 > -0.000000001 ++1.000000000 > -0.000000002 ++1.000000000 > -1.000000000 ++1.000000000 > -1.000000001 ++1.000000000 > -1.000000002 ++1.000000000 > -2.000000000 ++1.000000000 > -2.000000001 ++1.000000000 > -2.000000002 +======== ++1.000000001 > +0.000000000 ++1.000000001 > +0.000000001 ++1.000000001 > +0.000000002 ++1.000000001 > +1.000000000 ++1.000000001 = +1.000000001 ++1.000000001 < +1.000000002 ++1.000000001 < +2.000000000 ++1.000000001 < +2.000000001 ++1.000000001 < +2.000000002 +==== ++1.000000001 > -0.000000001 ++1.000000001 > -0.000000002 ++1.000000001 > -1.000000000 ++1.000000001 > -1.000000001 ++1.000000001 > -1.000000002 ++1.000000001 > -2.000000000 ++1.000000001 > -2.000000001 ++1.000000001 > -2.000000002 +======== ++1.000000002 > +0.000000000 ++1.000000002 > +0.000000001 ++1.000000002 > +0.000000002 ++1.000000002 > +1.000000000 ++1.000000002 > +1.000000001 ++1.000000002 = +1.000000002 ++1.000000002 < +2.000000000 ++1.000000002 < +2.000000001 ++1.000000002 < +2.000000002 +==== ++1.000000002 > -0.000000001 ++1.000000002 > -0.000000002 ++1.000000002 > -1.000000000 ++1.000000002 > -1.000000001 ++1.000000002 > -1.000000002 ++1.000000002 > -2.000000000 ++1.000000002 > -2.000000001 ++1.000000002 > -2.000000002 +======== ++2.000000000 > +0.000000000 ++2.000000000 > +0.000000001 ++2.000000000 > +0.000000002 ++2.000000000 > +1.000000000 ++2.000000000 > +1.000000001 ++2.000000000 > +1.000000002 ++2.000000000 = +2.000000000 ++2.000000000 < +2.000000001 ++2.000000000 < +2.000000002 +==== ++2.000000000 > -0.000000001 ++2.000000000 > -0.000000002 ++2.000000000 > -1.000000000 ++2.000000000 > -1.000000001 ++2.000000000 > -1.000000002 ++2.000000000 > -2.000000000 ++2.000000000 > -2.000000001 ++2.000000000 > -2.000000002 +======== ++2.000000001 > +0.000000000 ++2.000000001 > +0.000000001 ++2.000000001 > +0.000000002 ++2.000000001 > +1.000000000 ++2.000000001 > +1.000000001 ++2.000000001 > +1.000000002 ++2.000000001 > +2.000000000 ++2.000000001 = +2.000000001 ++2.000000001 < +2.000000002 +==== ++2.000000001 > -0.000000001 ++2.000000001 > -0.000000002 ++2.000000001 > -1.000000000 ++2.000000001 > -1.000000001 ++2.000000001 > -1.000000002 ++2.000000001 > -2.000000000 ++2.000000001 > -2.000000001 ++2.000000001 > -2.000000002 +======== ++2.000000002 > +0.000000000 ++2.000000002 > +0.000000001 ++2.000000002 > +0.000000002 ++2.000000002 > +1.000000000 ++2.000000002 > +1.000000001 ++2.000000002 > +1.000000002 ++2.000000002 > +2.000000000 ++2.000000002 > +2.000000001 ++2.000000002 = +2.000000002 +==== ++2.000000002 > -0.000000001 ++2.000000002 > -0.000000002 ++2.000000002 > -1.000000000 ++2.000000002 > -1.000000001 ++2.000000002 > -1.000000002 ++2.000000002 > -2.000000000 ++2.000000002 > -2.000000001 ++2.000000002 > -2.000000002 +======== +-0.000000001 < +0.000000000 +-0.000000001 < +0.000000001 +-0.000000001 < +0.000000002 +-0.000000001 < +1.000000000 +-0.000000001 < +1.000000001 +-0.000000001 < +1.000000002 +-0.000000001 < +2.000000000 +-0.000000001 < +2.000000001 +-0.000000001 < +2.000000002 +==== +-0.000000001 = -0.000000001 +-0.000000001 > -0.000000002 +-0.000000001 > -1.000000000 +-0.000000001 > -1.000000001 +-0.000000001 > -1.000000002 +-0.000000001 > -2.000000000 +-0.000000001 > -2.000000001 +-0.000000001 > -2.000000002 +======== +-0.000000002 < +0.000000000 +-0.000000002 < +0.000000001 +-0.000000002 < +0.000000002 +-0.000000002 < +1.000000000 +-0.000000002 < +1.000000001 +-0.000000002 < +1.000000002 +-0.000000002 < +2.000000000 +-0.000000002 < +2.000000001 +-0.000000002 < +2.000000002 +==== +-0.000000002 < -0.000000001 +-0.000000002 = -0.000000002 +-0.000000002 > -1.000000000 +-0.000000002 > -1.000000001 +-0.000000002 > -1.000000002 +-0.000000002 > -2.000000000 +-0.000000002 > -2.000000001 +-0.000000002 > -2.000000002 +======== +-1.000000000 < +0.000000000 +-1.000000000 < +0.000000001 +-1.000000000 < +0.000000002 +-1.000000000 < +1.000000000 +-1.000000000 < +1.000000001 +-1.000000000 < +1.000000002 +-1.000000000 < +2.000000000 +-1.000000000 < +2.000000001 +-1.000000000 < +2.000000002 +==== +-1.000000000 < -0.000000001 +-1.000000000 < -0.000000002 +-1.000000000 = -1.000000000 +-1.000000000 > -1.000000001 +-1.000000000 > -1.000000002 +-1.000000000 > -2.000000000 +-1.000000000 > -2.000000001 +-1.000000000 > -2.000000002 +======== +-1.000000001 < +0.000000000 +-1.000000001 < +0.000000001 +-1.000000001 < +0.000000002 +-1.000000001 < +1.000000000 +-1.000000001 < +1.000000001 +-1.000000001 < +1.000000002 +-1.000000001 < +2.000000000 +-1.000000001 < +2.000000001 +-1.000000001 < +2.000000002 +==== +-1.000000001 < -0.000000001 +-1.000000001 < -0.000000002 +-1.000000001 < -1.000000000 +-1.000000001 = -1.000000001 +-1.000000001 > -1.000000002 +-1.000000001 > -2.000000000 +-1.000000001 > -2.000000001 +-1.000000001 > -2.000000002 +======== +-1.000000002 < +0.000000000 +-1.000000002 < +0.000000001 +-1.000000002 < +0.000000002 +-1.000000002 < +1.000000000 +-1.000000002 < +1.000000001 +-1.000000002 < +1.000000002 +-1.000000002 < +2.000000000 +-1.000000002 < +2.000000001 +-1.000000002 < +2.000000002 +==== +-1.000000002 < -0.000000001 +-1.000000002 < -0.000000002 +-1.000000002 < -1.000000000 +-1.000000002 < -1.000000001 +-1.000000002 = -1.000000002 +-1.000000002 > -2.000000000 +-1.000000002 > -2.000000001 +-1.000000002 > -2.000000002 +======== +-2.000000000 < +0.000000000 +-2.000000000 < +0.000000001 +-2.000000000 < +0.000000002 +-2.000000000 < +1.000000000 +-2.000000000 < +1.000000001 +-2.000000000 < +1.000000002 +-2.000000000 < +2.000000000 +-2.000000000 < +2.000000001 +-2.000000000 < +2.000000002 +==== +-2.000000000 < -0.000000001 +-2.000000000 < -0.000000002 +-2.000000000 < -1.000000000 +-2.000000000 < -1.000000001 +-2.000000000 < -1.000000002 +-2.000000000 = -2.000000000 +-2.000000000 > -2.000000001 +-2.000000000 > -2.000000002 +======== +-2.000000001 < +0.000000000 +-2.000000001 < +0.000000001 +-2.000000001 < +0.000000002 +-2.000000001 < +1.000000000 +-2.000000001 < +1.000000001 +-2.000000001 < +1.000000002 +-2.000000001 < +2.000000000 +-2.000000001 < +2.000000001 +-2.000000001 < +2.000000002 +==== +-2.000000001 < -0.000000001 +-2.000000001 < -0.000000002 +-2.000000001 < -1.000000000 +-2.000000001 < -1.000000001 +-2.000000001 < -1.000000002 +-2.000000001 < -2.000000000 +-2.000000001 = -2.000000001 +-2.000000001 > -2.000000002 +======== +-2.000000002 < +0.000000000 +-2.000000002 < +0.000000001 +-2.000000002 < +0.000000002 +-2.000000002 < +1.000000000 +-2.000000002 < +1.000000001 +-2.000000002 < +1.000000002 +-2.000000002 < +2.000000000 +-2.000000002 < +2.000000001 +-2.000000002 < +2.000000002 +==== +-2.000000002 < -0.000000001 +-2.000000002 < -0.000000002 +-2.000000002 < -1.000000000 +-2.000000002 < -1.000000001 +-2.000000002 < -1.000000002 +-2.000000002 < -2.000000000 +-2.000000002 < -2.000000001 +-2.000000002 = -2.000000002 diff --git a/ext/date/tests/time/duration/methods/divideBy.phpt b/ext/date/tests/time/duration/methods/divideBy.phpt new file mode 100644 index 000000000000..440107d33ed4 --- /dev/null +++ b/ext/date/tests/time/duration/methods/divideBy.phpt @@ -0,0 +1,133 @@ +--TEST-- +Time\Duration::divideBy() +--FILE-- +divideBy($divisor); + echo f($d), " / ", sprintf("%10d", $divisor), " = ", f($result), PHP_EOL; + + if (PHP_INT_SIZE != 4 && (intdiv(as_int($d), $divisor) !== as_int($result))) { + throw new \Exception('Verification failed'); + } + } +} + +echo "========", PHP_EOL; + +$d = Time\Duration::fromSeconds(1, 0); +try { + $d->divideBy(0); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +======== + +0.000000000 / 1 = +0.000000000 + +0.000000000 / 2 = +0.000000000 + +0.000000000 / 3 = +0.000000000 + +0.000000000 / 4 = +0.000000000 + +0.000000000 / 999999999 = +0.000000000 + +0.000000000 / 1000000000 = +0.000000000 + +0.000000000 / 2147483647 = +0.000000000 +======== + +0.000000001 / 1 = +0.000000001 + +0.000000001 / 2 = +0.000000000 + +0.000000001 / 3 = +0.000000000 + +0.000000001 / 4 = +0.000000000 + +0.000000001 / 999999999 = +0.000000000 + +0.000000001 / 1000000000 = +0.000000000 + +0.000000001 / 2147483647 = +0.000000000 +======== + +0.999999999 / 1 = +0.999999999 + +0.999999999 / 2 = +0.499999999 + +0.999999999 / 3 = +0.333333333 + +0.999999999 / 4 = +0.249999999 + +0.999999999 / 999999999 = +0.000000001 + +0.999999999 / 1000000000 = +0.000000000 + +0.999999999 / 2147483647 = +0.000000000 +======== + +1.000000000 / 1 = +1.000000000 + +1.000000000 / 2 = +0.500000000 + +1.000000000 / 3 = +0.333333333 + +1.000000000 / 4 = +0.250000000 + +1.000000000 / 999999999 = +0.000000001 + +1.000000000 / 1000000000 = +0.000000001 + +1.000000000 / 2147483647 = +0.000000000 +======== ++2147483647.999999999 / 1 = +2147483647.999999999 ++2147483647.999999999 / 2 = +1073741823.999999999 ++2147483647.999999999 / 3 = +715827882.666666666 ++2147483647.999999999 / 4 = +536870911.999999999 ++2147483647.999999999 / 999999999 = +2.147483650 ++2147483647.999999999 / 1000000000 = +2.147483647 ++2147483647.999999999 / 2147483647 = +1.000000000 +======== + -0.000000001 / 1 = -0.000000001 + -0.000000001 / 2 = +0.000000000 + -0.000000001 / 3 = +0.000000000 + -0.000000001 / 4 = +0.000000000 + -0.000000001 / 999999999 = +0.000000000 + -0.000000001 / 1000000000 = +0.000000000 + -0.000000001 / 2147483647 = +0.000000000 +======== + -0.999999999 / 1 = -0.999999999 + -0.999999999 / 2 = -0.499999999 + -0.999999999 / 3 = -0.333333333 + -0.999999999 / 4 = -0.249999999 + -0.999999999 / 999999999 = -0.000000001 + -0.999999999 / 1000000000 = +0.000000000 + -0.999999999 / 2147483647 = +0.000000000 +======== + -1.000000000 / 1 = -1.000000000 + -1.000000000 / 2 = -0.500000000 + -1.000000000 / 3 = -0.333333333 + -1.000000000 / 4 = -0.250000000 + -1.000000000 / 999999999 = -0.000000001 + -1.000000000 / 1000000000 = -0.000000001 + -1.000000000 / 2147483647 = +0.000000000 +======== +-2147483647.999999999 / 1 = -2147483647.999999999 +-2147483647.999999999 / 2 = -1073741823.999999999 +-2147483647.999999999 / 3 = -715827882.666666666 +-2147483647.999999999 / 4 = -536870911.999999999 +-2147483647.999999999 / 999999999 = -2.147483650 +-2147483647.999999999 / 1000000000 = -2.147483647 +-2147483647.999999999 / 2147483647 = -1.000000000 +======== +DivisionByZeroError: Division by zero diff --git a/ext/date/tests/time/duration/methods/divideBy_64.phpt b/ext/date/tests/time/duration/methods/divideBy_64.phpt new file mode 100644 index 000000000000..21c54538f40b --- /dev/null +++ b/ext/date/tests/time/duration/methods/divideBy_64.phpt @@ -0,0 +1,78 @@ +--TEST-- +Time\Duration::divideBy() (64 bit variation) +--SKIPIF-- + +--FILE-- +divideBy($factor)), PHP_EOL; + } +} + +?> +--EXPECT-- +======== ++2147483648.000000000 / 1 = +2147483648.000000000 ++2147483648.000000000 / 2 = +1073741824.000000000 ++2147483648.000000000 / 3 = +715827882.666666666 ++2147483648.000000000 / 4 = +536870912.000000000 ++2147483648.000000000 / 999999999 = +2.147483650 ++2147483648.000000000 / 1000000000 = +2.147483648 ++2147483648.000000000 / 9223372035999999999 = +0.000000000 +======== ++9223372035.999999999 / 1 = +9223372035.999999999 ++9223372035.999999999 / 2 = +4611686017.999999999 ++9223372035.999999999 / 3 = +3074457345.333333333 ++9223372035.999999999 / 4 = +2305843008.999999999 ++9223372035.999999999 / 999999999 = +9.223372045 ++9223372035.999999999 / 1000000000 = +9.223372035 ++9223372035.999999999 / 9223372035999999999 = +0.000000001 +======== +-2147483648.000000000 / 1 = -2147483648.000000000 +-2147483648.000000000 / 2 = -1073741824.000000000 +-2147483648.000000000 / 3 = -715827882.666666666 +-2147483648.000000000 / 4 = -536870912.000000000 +-2147483648.000000000 / 999999999 = -2.147483650 +-2147483648.000000000 / 1000000000 = -2.147483648 +-2147483648.000000000 / 9223372035999999999 = +0.000000000 +======== +-9223372035.999999999 / 1 = -9223372035.999999999 +-9223372035.999999999 / 2 = -4611686017.999999999 +-9223372035.999999999 / 3 = -3074457345.333333333 +-9223372035.999999999 / 4 = -2305843008.999999999 +-9223372035.999999999 / 999999999 = -9.223372045 +-9223372035.999999999 / 1000000000 = -9.223372035 +-9223372035.999999999 / 9223372035999999999 = -0.000000001 diff --git a/ext/date/tests/time/duration/methods/fromHours.phpt b/ext/date/tests/time/duration/methods/fromHours.phpt new file mode 100644 index 000000000000..658288036433 --- /dev/null +++ b/ext/date/tests/time/duration/methods/fromHours.phpt @@ -0,0 +1,23 @@ +--TEST-- +Time\Duration::fromHours() +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECT-- + +0.000000000 + +3600.000000000 ++2147482800.000000000 +ValueError: Time\Duration::fromHours(): Argument #1 ($hours) must be greater than or equal to 0 diff --git a/ext/date/tests/time/duration/methods/fromHours_32.phpt b/ext/date/tests/time/duration/methods/fromHours_32.phpt new file mode 100644 index 000000000000..998ab5d9beaf --- /dev/null +++ b/ext/date/tests/time/duration/methods/fromHours_32.phpt @@ -0,0 +1,23 @@ +--TEST-- +Time\Duration::fromHours() (32 bit variation) +--SKIPIF-- + +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECTF-- ++2147482800.000000000 +Time\TimeException: The maximum representable range is 2_147_483_647 seconds (roughly 68 years) diff --git a/ext/date/tests/time/duration/methods/fromHours_64.phpt b/ext/date/tests/time/duration/methods/fromHours_64.phpt new file mode 100644 index 000000000000..719da0e88e20 --- /dev/null +++ b/ext/date/tests/time/duration/methods/fromHours_64.phpt @@ -0,0 +1,23 @@ +--TEST-- +Time\Duration::fromHours() (64 bit variation) +--SKIPIF-- + +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECT-- ++9223369200.000000000 +Time\TimeException: The maximum representable range is 9_223_372_035 seconds (roughly 292 years) diff --git a/ext/date/tests/time/duration/methods/fromIso8601DurationString.phpt b/ext/date/tests/time/duration/methods/fromIso8601DurationString.phpt new file mode 100644 index 000000000000..109a1dd1307a --- /dev/null +++ b/ext/date/tests/time/duration/methods/fromIso8601DurationString.phpt @@ -0,0 +1,74 @@ +--TEST-- +Time\Duration::fromIso8601DurationString() +--FILE-- +getMessage(), PHP_EOL; + } +} + +?> +--EXPECT-- +PT0S : +0.000000000 +PT1S : +1.000000000 +PT60S : +60.000000000 +PT2147483647S : +2147483647.000000000 +PT0.1S : Time\TimeException: The ISO 8601 duration string could not be parsed +PT0M : +0.000000000 +PT1M : +60.000000000 +PT1M1S : +61.000000000 +PT1M60S : +120.000000000 +PT0H : +0.000000000 +PT1H : +3600.000000000 +PT1H1M : +3660.000000000 +PT1H1M1S : +3661.000000000 +PT1H60M : +7200.000000000 +PT1H60M60S : +7260.000000000 + : Time\TimeException: The ISO 8601 duration string could not be parsed +P : Time\TimeException: The ISO 8601 duration string could not be parsed +PT : Time\TimeException: The ISO 8601 duration string could not be parsed +P1D : Time\TimeException: The ISO 8601 duration string may only contain the time (T) aspect +P1W : Time\TimeException: The ISO 8601 duration string may only contain the time (T) aspect +P1M : Time\TimeException: The ISO 8601 duration string may only contain the time (T) aspect +P1DT0S : Time\TimeException: The ISO 8601 duration string may only contain the time (T) aspect +2000-01-01T00:00:00Z : Time\TimeException: The ISO 8601 duration string is missing the period (P) aspect +2000-01-01T00:00:00Z/PT1H: Time\TimeException: The ISO 8601 duration string may only contain the period (P) aspect diff --git a/ext/date/tests/time/duration/methods/fromIso8601DurationString_64.phpt b/ext/date/tests/time/duration/methods/fromIso8601DurationString_64.phpt new file mode 100644 index 000000000000..04ee27db4660 --- /dev/null +++ b/ext/date/tests/time/duration/methods/fromIso8601DurationString_64.phpt @@ -0,0 +1,32 @@ +--TEST-- +Time\Duration::fromIso8601DurationString() (64 bit variation) +--SKIPIF-- + +--FILE-- +getMessage(), PHP_EOL; + } +} + +?> +--EXPECT-- +PT2147483648S : +2147483648.000000000 +PT9223372035S : +9223372035.000000000 +PT9223372036S : Time\TimeException: The maximum representable range is 9_223_372_035 seconds (roughly 292 years) diff --git a/ext/date/tests/time/duration/methods/fromMicroseconds.phpt b/ext/date/tests/time/duration/methods/fromMicroseconds.phpt new file mode 100644 index 000000000000..aef4092b9094 --- /dev/null +++ b/ext/date/tests/time/duration/methods/fromMicroseconds.phpt @@ -0,0 +1,27 @@ +--TEST-- +Time\Duration::fromMicroseconds() +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECT-- + +0.000000000 + +0.000001000 + +0.999999000 + +1.000000000 + +2147.483647000 +ValueError: Time\Duration::fromMicroseconds(): Argument #1 ($microseconds) must be greater than or equal to 0 diff --git a/ext/date/tests/time/duration/methods/fromMicroseconds_64.phpt b/ext/date/tests/time/duration/methods/fromMicroseconds_64.phpt new file mode 100644 index 000000000000..84f317425a44 --- /dev/null +++ b/ext/date/tests/time/duration/methods/fromMicroseconds_64.phpt @@ -0,0 +1,23 @@ +--TEST-- +Time\Duration::fromMicroseconds() (64 bit variation) +--SKIPIF-- + +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECT-- ++9223372035.999999000 +Time\TimeException: The maximum representable range is 9_223_372_035 seconds (roughly 292 years) diff --git a/ext/date/tests/time/duration/methods/fromMilliseconds.phpt b/ext/date/tests/time/duration/methods/fromMilliseconds.phpt new file mode 100644 index 000000000000..d63f20535b4b --- /dev/null +++ b/ext/date/tests/time/duration/methods/fromMilliseconds.phpt @@ -0,0 +1,27 @@ +--TEST-- +Time\Duration::fromMilliseconds() +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECT-- + +0.000000000 + +0.001000000 + +0.999000000 + +1.000000000 + +2147483.647000000 +ValueError: Time\Duration::fromMilliseconds(): Argument #1 ($milliseconds) must be greater than or equal to 0 diff --git a/ext/date/tests/time/duration/methods/fromMilliseconds_64.phpt b/ext/date/tests/time/duration/methods/fromMilliseconds_64.phpt new file mode 100644 index 000000000000..4ed7250fb38a --- /dev/null +++ b/ext/date/tests/time/duration/methods/fromMilliseconds_64.phpt @@ -0,0 +1,23 @@ +--TEST-- +Time\Duration::fromMilliseconds() (64 bit variation) +--SKIPIF-- + +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECT-- ++9223372035.999000000 +Time\TimeException: The maximum representable range is 9_223_372_035 seconds (roughly 292 years) diff --git a/ext/date/tests/time/duration/methods/fromMinutes.phpt b/ext/date/tests/time/duration/methods/fromMinutes.phpt new file mode 100644 index 000000000000..7674ea95f54c --- /dev/null +++ b/ext/date/tests/time/duration/methods/fromMinutes.phpt @@ -0,0 +1,23 @@ +--TEST-- +Time\Duration::fromMinutes() +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECT-- + +0.000000000 + +60.000000000 ++2147483640.000000000 +ValueError: Time\Duration::fromMinutes(): Argument #1 ($minutes) must be greater than or equal to 0 diff --git a/ext/date/tests/time/duration/methods/fromMinutes_32.phpt b/ext/date/tests/time/duration/methods/fromMinutes_32.phpt new file mode 100644 index 000000000000..705823165df6 --- /dev/null +++ b/ext/date/tests/time/duration/methods/fromMinutes_32.phpt @@ -0,0 +1,23 @@ +--TEST-- +Time\Duration::fromMinutes() (32 bit variation) +--SKIPIF-- + +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECTF-- ++2147483640.000000000 +Time\TimeException: The maximum representable range is 2_147_483_647 seconds (roughly 68 years) diff --git a/ext/date/tests/time/duration/methods/fromMinutes_64.phpt b/ext/date/tests/time/duration/methods/fromMinutes_64.phpt new file mode 100644 index 000000000000..4b3eaf4ad26c --- /dev/null +++ b/ext/date/tests/time/duration/methods/fromMinutes_64.phpt @@ -0,0 +1,23 @@ +--TEST-- +Time\Duration::fromMinutes() (64 bit variation) +--SKIPIF-- + +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECT-- ++9223372020.000000000 +Time\TimeException: The maximum representable range is 9_223_372_035 seconds (roughly 292 years) diff --git a/ext/date/tests/time/duration/methods/fromNanoseconds.phpt b/ext/date/tests/time/duration/methods/fromNanoseconds.phpt new file mode 100644 index 000000000000..7b425d2eb562 --- /dev/null +++ b/ext/date/tests/time/duration/methods/fromNanoseconds.phpt @@ -0,0 +1,27 @@ +--TEST-- +Time\Duration::fromNanoseconds() +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECT-- + +0.000000000 + +0.000000001 + +0.999999999 + +1.000000000 + +2.147483647 +ValueError: Time\Duration::fromNanoseconds(): Argument #1 ($nanoseconds) must be greater than or equal to 0 diff --git a/ext/date/tests/time/duration/methods/fromNanoseconds_64.phpt b/ext/date/tests/time/duration/methods/fromNanoseconds_64.phpt new file mode 100644 index 000000000000..e68adc28e4a3 --- /dev/null +++ b/ext/date/tests/time/duration/methods/fromNanoseconds_64.phpt @@ -0,0 +1,23 @@ +--TEST-- +Time\Duration::fromNanoseconds() (64 bit variation) +--SKIPIF-- + +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECT-- ++9223372035.999999999 +Time\TimeException: The maximum representable range is 9_223_372_035 seconds (roughly 292 years) diff --git a/ext/date/tests/time/duration/methods/fromSeconds.phpt b/ext/date/tests/time/duration/methods/fromSeconds.phpt new file mode 100644 index 000000000000..8cd26ce4c725 --- /dev/null +++ b/ext/date/tests/time/duration/methods/fromSeconds.phpt @@ -0,0 +1,46 @@ +--TEST-- +Time\Duration::fromSeconds() +--FILE-- +getMessage(), PHP_EOL; +} + +try { + Time\Duration::fromSeconds(0, -1); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +try { + Time\Duration::fromSeconds(0, 1000000000); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- + +0.000000000 + +1.000000000 ++2147483647.000000000 + +0.000000000 + +0.000000001 + +1.000000001 ++2147483647.999999999 +ValueError: Time\Duration::fromSeconds(): Argument #1 ($seconds) must be greater than or equal to 0 +ValueError: Time\Duration::fromSeconds(): Argument #2 ($nanoseconds) must be greater than or equal to 0 +ValueError: Time\Duration::fromSeconds(): Argument #2 ($nanoseconds) must be less than 1_000_000_000 diff --git a/ext/date/tests/time/duration/methods/fromSeconds_64.phpt b/ext/date/tests/time/duration/methods/fromSeconds_64.phpt new file mode 100644 index 000000000000..2deed85ec0e8 --- /dev/null +++ b/ext/date/tests/time/duration/methods/fromSeconds_64.phpt @@ -0,0 +1,25 @@ +--TEST-- +Time\Duration::fromSeconds() (64 bit variation) +--SKIPIF-- + +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECT-- ++9223372035.000000000 ++9223372035.999999999 +Time\TimeException: The maximum representable range is 9_223_372_035 seconds (roughly 292 years) diff --git a/ext/date/tests/time/duration/methods/multiplyBy.phpt b/ext/date/tests/time/duration/methods/multiplyBy.phpt new file mode 100644 index 000000000000..70b374d28c2b --- /dev/null +++ b/ext/date/tests/time/duration/methods/multiplyBy.phpt @@ -0,0 +1,206 @@ +--TEST-- +Time\Duration::multiplyBy() +--FILE-- +multiplyBy($factor); + echo f($d), " * ", sprintf("%10d", $factor), " = ", f($result), PHP_EOL; + + if (PHP_INT_SIZE != 4 && (as_int($d) * $factor !== as_int($result))) { + throw new \Exception('Verification failed'); + } + } +} + +echo "========", PHP_EOL; +$d = Time\Duration::fromSeconds(0, 1); +$factor = 2_147_483_647; +$result = $d->multiplyBy($factor); +echo f($d), " * ", sprintf("%10d", $factor), " = ", f($result), PHP_EOL; + +echo "========", PHP_EOL; +$d = Time\Duration::fromSeconds(1, 0); +$factor = 2_147_483_647; +$result = $d->multiplyBy($factor); +echo f($d), " * ", sprintf("%10d", $factor), " = ", f($result), PHP_EOL; + +?> +--EXPECT-- +======== + +0.000000000 * 0 = +0.000000000 + +0.000000000 * 1 = +0.000000000 + +0.000000000 * 2 = +0.000000000 + +0.000000000 * 3 = +0.000000000 + +0.000000000 * 4 = +0.000000000 + +0.000000000 * 999999999 = +0.000000000 + +0.000000000 * 1000000000 = +0.000000000 +======== + +0.000000001 * 0 = +0.000000000 + +0.000000001 * 1 = +0.000000001 + +0.000000001 * 2 = +0.000000002 + +0.000000001 * 3 = +0.000000003 + +0.000000001 * 4 = +0.000000004 + +0.000000001 * 999999999 = +0.999999999 + +0.000000001 * 1000000000 = +1.000000000 +======== + +0.000000002 * 0 = +0.000000000 + +0.000000002 * 1 = +0.000000002 + +0.000000002 * 2 = +0.000000004 + +0.000000002 * 3 = +0.000000006 + +0.000000002 * 4 = +0.000000008 + +0.000000002 * 999999999 = +1.999999998 + +0.000000002 * 1000000000 = +2.000000000 +======== + +1.000000000 * 0 = +0.000000000 + +1.000000000 * 1 = +1.000000000 + +1.000000000 * 2 = +2.000000000 + +1.000000000 * 3 = +3.000000000 + +1.000000000 * 4 = +4.000000000 + +1.000000000 * 999999999 = +999999999.000000000 + +1.000000000 * 1000000000 = +1000000000.000000000 +======== + +1.000000001 * 0 = +0.000000000 + +1.000000001 * 1 = +1.000000001 + +1.000000001 * 2 = +2.000000002 + +1.000000001 * 3 = +3.000000003 + +1.000000001 * 4 = +4.000000004 + +1.000000001 * 999999999 = +999999999.999999999 + +1.000000001 * 1000000000 = +1000000001.000000000 +======== + +1.000000002 * 0 = +0.000000000 + +1.000000002 * 1 = +1.000000002 + +1.000000002 * 2 = +2.000000004 + +1.000000002 * 3 = +3.000000006 + +1.000000002 * 4 = +4.000000008 + +1.000000002 * 999999999 = +1000000000.999999998 + +1.000000002 * 1000000000 = +1000000002.000000000 +======== + +2.000000000 * 0 = +0.000000000 + +2.000000000 * 1 = +2.000000000 + +2.000000000 * 2 = +4.000000000 + +2.000000000 * 3 = +6.000000000 + +2.000000000 * 4 = +8.000000000 + +2.000000000 * 999999999 = +1999999998.000000000 + +2.000000000 * 1000000000 = +2000000000.000000000 +======== + +2.000000001 * 0 = +0.000000000 + +2.000000001 * 1 = +2.000000001 + +2.000000001 * 2 = +4.000000002 + +2.000000001 * 3 = +6.000000003 + +2.000000001 * 4 = +8.000000004 + +2.000000001 * 999999999 = +1999999998.999999999 + +2.000000001 * 1000000000 = +2000000001.000000000 +======== + +2.000000002 * 0 = +0.000000000 + +2.000000002 * 1 = +2.000000002 + +2.000000002 * 2 = +4.000000004 + +2.000000002 * 3 = +6.000000006 + +2.000000002 * 4 = +8.000000008 + +2.000000002 * 999999999 = +1999999999.999999998 + +2.000000002 * 1000000000 = +2000000002.000000000 +======== + -0.000000001 * 0 = +0.000000000 + -0.000000001 * 1 = -0.000000001 + -0.000000001 * 2 = -0.000000002 + -0.000000001 * 3 = -0.000000003 + -0.000000001 * 4 = -0.000000004 + -0.000000001 * 999999999 = -0.999999999 + -0.000000001 * 1000000000 = -1.000000000 +======== + -0.000000002 * 0 = +0.000000000 + -0.000000002 * 1 = -0.000000002 + -0.000000002 * 2 = -0.000000004 + -0.000000002 * 3 = -0.000000006 + -0.000000002 * 4 = -0.000000008 + -0.000000002 * 999999999 = -1.999999998 + -0.000000002 * 1000000000 = -2.000000000 +======== + -1.000000000 * 0 = +0.000000000 + -1.000000000 * 1 = -1.000000000 + -1.000000000 * 2 = -2.000000000 + -1.000000000 * 3 = -3.000000000 + -1.000000000 * 4 = -4.000000000 + -1.000000000 * 999999999 = -999999999.000000000 + -1.000000000 * 1000000000 = -1000000000.000000000 +======== + -1.000000001 * 0 = +0.000000000 + -1.000000001 * 1 = -1.000000001 + -1.000000001 * 2 = -2.000000002 + -1.000000001 * 3 = -3.000000003 + -1.000000001 * 4 = -4.000000004 + -1.000000001 * 999999999 = -999999999.999999999 + -1.000000001 * 1000000000 = -1000000001.000000000 +======== + -1.000000002 * 0 = +0.000000000 + -1.000000002 * 1 = -1.000000002 + -1.000000002 * 2 = -2.000000004 + -1.000000002 * 3 = -3.000000006 + -1.000000002 * 4 = -4.000000008 + -1.000000002 * 999999999 = -1000000000.999999998 + -1.000000002 * 1000000000 = -1000000002.000000000 +======== + -2.000000000 * 0 = +0.000000000 + -2.000000000 * 1 = -2.000000000 + -2.000000000 * 2 = -4.000000000 + -2.000000000 * 3 = -6.000000000 + -2.000000000 * 4 = -8.000000000 + -2.000000000 * 999999999 = -1999999998.000000000 + -2.000000000 * 1000000000 = -2000000000.000000000 +======== + -2.000000001 * 0 = +0.000000000 + -2.000000001 * 1 = -2.000000001 + -2.000000001 * 2 = -4.000000002 + -2.000000001 * 3 = -6.000000003 + -2.000000001 * 4 = -8.000000004 + -2.000000001 * 999999999 = -1999999998.999999999 + -2.000000001 * 1000000000 = -2000000001.000000000 +======== + -2.000000002 * 0 = +0.000000000 + -2.000000002 * 1 = -2.000000002 + -2.000000002 * 2 = -4.000000004 + -2.000000002 * 3 = -6.000000006 + -2.000000002 * 4 = -8.000000008 + -2.000000002 * 999999999 = -1999999999.999999998 + -2.000000002 * 1000000000 = -2000000002.000000000 +======== + +0.000000001 * 2147483647 = +2.147483647 +======== + +1.000000000 * 2147483647 = +2147483647.000000000 diff --git a/ext/date/tests/time/duration/methods/multiplyBy_32.phpt b/ext/date/tests/time/duration/methods/multiplyBy_32.phpt new file mode 100644 index 000000000000..7a1cbcb56065 --- /dev/null +++ b/ext/date/tests/time/duration/methods/multiplyBy_32.phpt @@ -0,0 +1,55 @@ +--TEST-- +Time\Duration::multiplyBy() (32 bit variation) +--SKIPIF-- + +--FILE-- +multiplyBy(1)), PHP_EOL; + +try { + $d->multiplyBy(2); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +echo "====", PHP_EOL; + +$d = Time\Duration::fromSeconds(1_073_741_823, 999999999); + +echo f($d->multiplyBy(2)), PHP_EOL; + +try { + $d->multiplyBy(3); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +echo "====", PHP_EOL; + +$d = Time\Duration::fromSeconds(715_827_882, 666666666); + +echo f($d->multiplyBy(3)), PHP_EOL; + +try { + $d->multiplyBy(4); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- ++2147483647.999999999 +Time\TimeException: The maximum representable range is 2_147_483_647 seconds (roughly 68 years) +==== ++2147483647.999999998 +Time\TimeException: The maximum representable range is 2_147_483_647 seconds (roughly 68 years) +==== ++2147483647.999999998 +Time\TimeException: The maximum representable range is 2_147_483_647 seconds (roughly 68 years) diff --git a/ext/date/tests/time/duration/methods/multiplyBy_64.phpt b/ext/date/tests/time/duration/methods/multiplyBy_64.phpt new file mode 100644 index 000000000000..04b220fe2dbc --- /dev/null +++ b/ext/date/tests/time/duration/methods/multiplyBy_64.phpt @@ -0,0 +1,70 @@ +--TEST-- +Time\Duration::multiplyBy() (64 bit variation) +--SKIPIF-- + +--FILE-- +multiplyBy(1)), PHP_EOL; + +try { + $d->multiplyBy(2); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +echo "====", PHP_EOL; + +$d = Time\Duration::fromSeconds(4_611_686_017, 999999999); + +echo f($d->multiplyBy(2)), PHP_EOL; + +try { + $d->multiplyBy(3); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +echo "====", PHP_EOL; + +$d = Time\Duration::fromSeconds(3_074_457_345, 333333333); + +echo f($d->multiplyBy(3)), PHP_EOL; + +try { + $d->multiplyBy(4); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +echo "====", PHP_EOL; + +$d = Time\Duration::fromSeconds(0, 1); + +echo f($d->multiplyBy(9_223_372_035_999999999)), PHP_EOL; + +try { + $d->multiplyBy(9_223_372_036_000000000); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- ++9223372035.999999999 +Time\TimeException: The maximum representable range is 9_223_372_035 seconds (roughly 292 years) +==== ++9223372035.999999998 +Time\TimeException: The maximum representable range is 9_223_372_035 seconds (roughly 292 years) +==== ++9223372035.999999999 +Time\TimeException: The maximum representable range is 9_223_372_035 seconds (roughly 292 years) +==== ++9223372035.999999999 +Time\TimeException: The maximum representable range is 9_223_372_035 seconds (roughly 292 years) diff --git a/ext/date/tests/time/duration/methods/negate.phpt b/ext/date/tests/time/duration/methods/negate.phpt new file mode 100644 index 000000000000..ce156cd20374 --- /dev/null +++ b/ext/date/tests/time/duration/methods/negate.phpt @@ -0,0 +1,29 @@ +--TEST-- +Time\Duration::negate() +--FILE-- +negate()), PHP_EOL; +echo f(Time\Duration::fromSeconds(0, 0)->negate()->negate()), PHP_EOL; + +echo f(Time\Duration::fromSeconds(1, 0)->negate()), PHP_EOL; +echo f(Time\Duration::fromSeconds(1, 0)->negate()->negate()), PHP_EOL; + +echo f(Time\Duration::fromSeconds(0, 1)->negate()), PHP_EOL; +echo f(Time\Duration::fromSeconds(0, 1)->negate()->negate()), PHP_EOL; + +echo f(Time\Duration::fromSeconds(1, 1)->negate()), PHP_EOL; +echo f(Time\Duration::fromSeconds(1, 1)->negate()->negate()), PHP_EOL; + +?> +--EXPECT-- + +0.000000000 + +0.000000000 + -1.000000000 + +1.000000000 + -0.000000001 + +0.000000001 + -1.000000001 + +1.000000001 diff --git a/ext/date/tests/time/duration/methods/sub.phpt b/ext/date/tests/time/duration/methods/sub.phpt new file mode 100644 index 000000000000..5552a249d9bf --- /dev/null +++ b/ext/date/tests/time/duration/methods/sub.phpt @@ -0,0 +1,371 @@ +--TEST-- +Time\Duration::sub() +--FILE-- +sub($b); + echo f($a, pad: false, plus_sign: false), " - ", f($b, pad: false, plus_sign: false), " = ", f($result, pad: false), PHP_EOL; + if (PHP_INT_SIZE != 4 && (as_int($a) - as_int($b) !== as_int($result))) { + throw new \Exception('Verification failed'); + } + } +} + +?> +--EXPECT-- +======== + 0.000000000 - 0.000000000 = +0.000000000 + 0.000000000 - 0.000000001 = -0.000000001 + 0.000000000 - 0.000000002 = -0.000000002 + 0.000000000 - 1.000000000 = -1.000000000 + 0.000000000 - 1.000000001 = -1.000000001 + 0.000000000 - 1.000000002 = -1.000000002 + 0.000000000 - 2.000000000 = -2.000000000 + 0.000000000 - 2.000000001 = -2.000000001 + 0.000000000 - 2.000000002 = -2.000000002 +==== + 0.000000000 - -0.000000001 = +0.000000001 + 0.000000000 - -0.000000002 = +0.000000002 + 0.000000000 - -1.000000000 = +1.000000000 + 0.000000000 - -1.000000001 = +1.000000001 + 0.000000000 - -1.000000002 = +1.000000002 + 0.000000000 - -2.000000000 = +2.000000000 + 0.000000000 - -2.000000001 = +2.000000001 + 0.000000000 - -2.000000002 = +2.000000002 +======== + 0.000000001 - 0.000000000 = +0.000000001 + 0.000000001 - 0.000000001 = +0.000000000 + 0.000000001 - 0.000000002 = -0.000000001 + 0.000000001 - 1.000000000 = -0.999999999 + 0.000000001 - 1.000000001 = -1.000000000 + 0.000000001 - 1.000000002 = -1.000000001 + 0.000000001 - 2.000000000 = -1.999999999 + 0.000000001 - 2.000000001 = -2.000000000 + 0.000000001 - 2.000000002 = -2.000000001 +==== + 0.000000001 - -0.000000001 = +0.000000002 + 0.000000001 - -0.000000002 = +0.000000003 + 0.000000001 - -1.000000000 = +1.000000001 + 0.000000001 - -1.000000001 = +1.000000002 + 0.000000001 - -1.000000002 = +1.000000003 + 0.000000001 - -2.000000000 = +2.000000001 + 0.000000001 - -2.000000001 = +2.000000002 + 0.000000001 - -2.000000002 = +2.000000003 +======== + 0.000000002 - 0.000000000 = +0.000000002 + 0.000000002 - 0.000000001 = +0.000000001 + 0.000000002 - 0.000000002 = +0.000000000 + 0.000000002 - 1.000000000 = -0.999999998 + 0.000000002 - 1.000000001 = -0.999999999 + 0.000000002 - 1.000000002 = -1.000000000 + 0.000000002 - 2.000000000 = -1.999999998 + 0.000000002 - 2.000000001 = -1.999999999 + 0.000000002 - 2.000000002 = -2.000000000 +==== + 0.000000002 - -0.000000001 = +0.000000003 + 0.000000002 - -0.000000002 = +0.000000004 + 0.000000002 - -1.000000000 = +1.000000002 + 0.000000002 - -1.000000001 = +1.000000003 + 0.000000002 - -1.000000002 = +1.000000004 + 0.000000002 - -2.000000000 = +2.000000002 + 0.000000002 - -2.000000001 = +2.000000003 + 0.000000002 - -2.000000002 = +2.000000004 +======== + 1.000000000 - 0.000000000 = +1.000000000 + 1.000000000 - 0.000000001 = +0.999999999 + 1.000000000 - 0.000000002 = +0.999999998 + 1.000000000 - 1.000000000 = +0.000000000 + 1.000000000 - 1.000000001 = -0.000000001 + 1.000000000 - 1.000000002 = -0.000000002 + 1.000000000 - 2.000000000 = -1.000000000 + 1.000000000 - 2.000000001 = -1.000000001 + 1.000000000 - 2.000000002 = -1.000000002 +==== + 1.000000000 - -0.000000001 = +1.000000001 + 1.000000000 - -0.000000002 = +1.000000002 + 1.000000000 - -1.000000000 = +2.000000000 + 1.000000000 - -1.000000001 = +2.000000001 + 1.000000000 - -1.000000002 = +2.000000002 + 1.000000000 - -2.000000000 = +3.000000000 + 1.000000000 - -2.000000001 = +3.000000001 + 1.000000000 - -2.000000002 = +3.000000002 +======== + 1.000000001 - 0.000000000 = +1.000000001 + 1.000000001 - 0.000000001 = +1.000000000 + 1.000000001 - 0.000000002 = +0.999999999 + 1.000000001 - 1.000000000 = +0.000000001 + 1.000000001 - 1.000000001 = +0.000000000 + 1.000000001 - 1.000000002 = -0.000000001 + 1.000000001 - 2.000000000 = -0.999999999 + 1.000000001 - 2.000000001 = -1.000000000 + 1.000000001 - 2.000000002 = -1.000000001 +==== + 1.000000001 - -0.000000001 = +1.000000002 + 1.000000001 - -0.000000002 = +1.000000003 + 1.000000001 - -1.000000000 = +2.000000001 + 1.000000001 - -1.000000001 = +2.000000002 + 1.000000001 - -1.000000002 = +2.000000003 + 1.000000001 - -2.000000000 = +3.000000001 + 1.000000001 - -2.000000001 = +3.000000002 + 1.000000001 - -2.000000002 = +3.000000003 +======== + 1.000000002 - 0.000000000 = +1.000000002 + 1.000000002 - 0.000000001 = +1.000000001 + 1.000000002 - 0.000000002 = +1.000000000 + 1.000000002 - 1.000000000 = +0.000000002 + 1.000000002 - 1.000000001 = +0.000000001 + 1.000000002 - 1.000000002 = +0.000000000 + 1.000000002 - 2.000000000 = -0.999999998 + 1.000000002 - 2.000000001 = -0.999999999 + 1.000000002 - 2.000000002 = -1.000000000 +==== + 1.000000002 - -0.000000001 = +1.000000003 + 1.000000002 - -0.000000002 = +1.000000004 + 1.000000002 - -1.000000000 = +2.000000002 + 1.000000002 - -1.000000001 = +2.000000003 + 1.000000002 - -1.000000002 = +2.000000004 + 1.000000002 - -2.000000000 = +3.000000002 + 1.000000002 - -2.000000001 = +3.000000003 + 1.000000002 - -2.000000002 = +3.000000004 +======== + 2.000000000 - 0.000000000 = +2.000000000 + 2.000000000 - 0.000000001 = +1.999999999 + 2.000000000 - 0.000000002 = +1.999999998 + 2.000000000 - 1.000000000 = +1.000000000 + 2.000000000 - 1.000000001 = +0.999999999 + 2.000000000 - 1.000000002 = +0.999999998 + 2.000000000 - 2.000000000 = +0.000000000 + 2.000000000 - 2.000000001 = -0.000000001 + 2.000000000 - 2.000000002 = -0.000000002 +==== + 2.000000000 - -0.000000001 = +2.000000001 + 2.000000000 - -0.000000002 = +2.000000002 + 2.000000000 - -1.000000000 = +3.000000000 + 2.000000000 - -1.000000001 = +3.000000001 + 2.000000000 - -1.000000002 = +3.000000002 + 2.000000000 - -2.000000000 = +4.000000000 + 2.000000000 - -2.000000001 = +4.000000001 + 2.000000000 - -2.000000002 = +4.000000002 +======== + 2.000000001 - 0.000000000 = +2.000000001 + 2.000000001 - 0.000000001 = +2.000000000 + 2.000000001 - 0.000000002 = +1.999999999 + 2.000000001 - 1.000000000 = +1.000000001 + 2.000000001 - 1.000000001 = +1.000000000 + 2.000000001 - 1.000000002 = +0.999999999 + 2.000000001 - 2.000000000 = +0.000000001 + 2.000000001 - 2.000000001 = +0.000000000 + 2.000000001 - 2.000000002 = -0.000000001 +==== + 2.000000001 - -0.000000001 = +2.000000002 + 2.000000001 - -0.000000002 = +2.000000003 + 2.000000001 - -1.000000000 = +3.000000001 + 2.000000001 - -1.000000001 = +3.000000002 + 2.000000001 - -1.000000002 = +3.000000003 + 2.000000001 - -2.000000000 = +4.000000001 + 2.000000001 - -2.000000001 = +4.000000002 + 2.000000001 - -2.000000002 = +4.000000003 +======== + 2.000000002 - 0.000000000 = +2.000000002 + 2.000000002 - 0.000000001 = +2.000000001 + 2.000000002 - 0.000000002 = +2.000000000 + 2.000000002 - 1.000000000 = +1.000000002 + 2.000000002 - 1.000000001 = +1.000000001 + 2.000000002 - 1.000000002 = +1.000000000 + 2.000000002 - 2.000000000 = +0.000000002 + 2.000000002 - 2.000000001 = +0.000000001 + 2.000000002 - 2.000000002 = +0.000000000 +==== + 2.000000002 - -0.000000001 = +2.000000003 + 2.000000002 - -0.000000002 = +2.000000004 + 2.000000002 - -1.000000000 = +3.000000002 + 2.000000002 - -1.000000001 = +3.000000003 + 2.000000002 - -1.000000002 = +3.000000004 + 2.000000002 - -2.000000000 = +4.000000002 + 2.000000002 - -2.000000001 = +4.000000003 + 2.000000002 - -2.000000002 = +4.000000004 +======== +-0.000000001 - 0.000000000 = -0.000000001 +-0.000000001 - 0.000000001 = -0.000000002 +-0.000000001 - 0.000000002 = -0.000000003 +-0.000000001 - 1.000000000 = -1.000000001 +-0.000000001 - 1.000000001 = -1.000000002 +-0.000000001 - 1.000000002 = -1.000000003 +-0.000000001 - 2.000000000 = -2.000000001 +-0.000000001 - 2.000000001 = -2.000000002 +-0.000000001 - 2.000000002 = -2.000000003 +==== +-0.000000001 - -0.000000001 = +0.000000000 +-0.000000001 - -0.000000002 = +0.000000001 +-0.000000001 - -1.000000000 = +0.999999999 +-0.000000001 - -1.000000001 = +1.000000000 +-0.000000001 - -1.000000002 = +1.000000001 +-0.000000001 - -2.000000000 = +1.999999999 +-0.000000001 - -2.000000001 = +2.000000000 +-0.000000001 - -2.000000002 = +2.000000001 +======== +-0.000000002 - 0.000000000 = -0.000000002 +-0.000000002 - 0.000000001 = -0.000000003 +-0.000000002 - 0.000000002 = -0.000000004 +-0.000000002 - 1.000000000 = -1.000000002 +-0.000000002 - 1.000000001 = -1.000000003 +-0.000000002 - 1.000000002 = -1.000000004 +-0.000000002 - 2.000000000 = -2.000000002 +-0.000000002 - 2.000000001 = -2.000000003 +-0.000000002 - 2.000000002 = -2.000000004 +==== +-0.000000002 - -0.000000001 = -0.000000001 +-0.000000002 - -0.000000002 = +0.000000000 +-0.000000002 - -1.000000000 = +0.999999998 +-0.000000002 - -1.000000001 = +0.999999999 +-0.000000002 - -1.000000002 = +1.000000000 +-0.000000002 - -2.000000000 = +1.999999998 +-0.000000002 - -2.000000001 = +1.999999999 +-0.000000002 - -2.000000002 = +2.000000000 +======== +-1.000000000 - 0.000000000 = -1.000000000 +-1.000000000 - 0.000000001 = -1.000000001 +-1.000000000 - 0.000000002 = -1.000000002 +-1.000000000 - 1.000000000 = -2.000000000 +-1.000000000 - 1.000000001 = -2.000000001 +-1.000000000 - 1.000000002 = -2.000000002 +-1.000000000 - 2.000000000 = -3.000000000 +-1.000000000 - 2.000000001 = -3.000000001 +-1.000000000 - 2.000000002 = -3.000000002 +==== +-1.000000000 - -0.000000001 = -0.999999999 +-1.000000000 - -0.000000002 = -0.999999998 +-1.000000000 - -1.000000000 = +0.000000000 +-1.000000000 - -1.000000001 = +0.000000001 +-1.000000000 - -1.000000002 = +0.000000002 +-1.000000000 - -2.000000000 = +1.000000000 +-1.000000000 - -2.000000001 = +1.000000001 +-1.000000000 - -2.000000002 = +1.000000002 +======== +-1.000000001 - 0.000000000 = -1.000000001 +-1.000000001 - 0.000000001 = -1.000000002 +-1.000000001 - 0.000000002 = -1.000000003 +-1.000000001 - 1.000000000 = -2.000000001 +-1.000000001 - 1.000000001 = -2.000000002 +-1.000000001 - 1.000000002 = -2.000000003 +-1.000000001 - 2.000000000 = -3.000000001 +-1.000000001 - 2.000000001 = -3.000000002 +-1.000000001 - 2.000000002 = -3.000000003 +==== +-1.000000001 - -0.000000001 = -1.000000000 +-1.000000001 - -0.000000002 = -0.999999999 +-1.000000001 - -1.000000000 = -0.000000001 +-1.000000001 - -1.000000001 = +0.000000000 +-1.000000001 - -1.000000002 = +0.000000001 +-1.000000001 - -2.000000000 = +0.999999999 +-1.000000001 - -2.000000001 = +1.000000000 +-1.000000001 - -2.000000002 = +1.000000001 +======== +-1.000000002 - 0.000000000 = -1.000000002 +-1.000000002 - 0.000000001 = -1.000000003 +-1.000000002 - 0.000000002 = -1.000000004 +-1.000000002 - 1.000000000 = -2.000000002 +-1.000000002 - 1.000000001 = -2.000000003 +-1.000000002 - 1.000000002 = -2.000000004 +-1.000000002 - 2.000000000 = -3.000000002 +-1.000000002 - 2.000000001 = -3.000000003 +-1.000000002 - 2.000000002 = -3.000000004 +==== +-1.000000002 - -0.000000001 = -1.000000001 +-1.000000002 - -0.000000002 = -1.000000000 +-1.000000002 - -1.000000000 = -0.000000002 +-1.000000002 - -1.000000001 = -0.000000001 +-1.000000002 - -1.000000002 = +0.000000000 +-1.000000002 - -2.000000000 = +0.999999998 +-1.000000002 - -2.000000001 = +0.999999999 +-1.000000002 - -2.000000002 = +1.000000000 +======== +-2.000000000 - 0.000000000 = -2.000000000 +-2.000000000 - 0.000000001 = -2.000000001 +-2.000000000 - 0.000000002 = -2.000000002 +-2.000000000 - 1.000000000 = -3.000000000 +-2.000000000 - 1.000000001 = -3.000000001 +-2.000000000 - 1.000000002 = -3.000000002 +-2.000000000 - 2.000000000 = -4.000000000 +-2.000000000 - 2.000000001 = -4.000000001 +-2.000000000 - 2.000000002 = -4.000000002 +==== +-2.000000000 - -0.000000001 = -1.999999999 +-2.000000000 - -0.000000002 = -1.999999998 +-2.000000000 - -1.000000000 = -1.000000000 +-2.000000000 - -1.000000001 = -0.999999999 +-2.000000000 - -1.000000002 = -0.999999998 +-2.000000000 - -2.000000000 = +0.000000000 +-2.000000000 - -2.000000001 = +0.000000001 +-2.000000000 - -2.000000002 = +0.000000002 +======== +-2.000000001 - 0.000000000 = -2.000000001 +-2.000000001 - 0.000000001 = -2.000000002 +-2.000000001 - 0.000000002 = -2.000000003 +-2.000000001 - 1.000000000 = -3.000000001 +-2.000000001 - 1.000000001 = -3.000000002 +-2.000000001 - 1.000000002 = -3.000000003 +-2.000000001 - 2.000000000 = -4.000000001 +-2.000000001 - 2.000000001 = -4.000000002 +-2.000000001 - 2.000000002 = -4.000000003 +==== +-2.000000001 - -0.000000001 = -2.000000000 +-2.000000001 - -0.000000002 = -1.999999999 +-2.000000001 - -1.000000000 = -1.000000001 +-2.000000001 - -1.000000001 = -1.000000000 +-2.000000001 - -1.000000002 = -0.999999999 +-2.000000001 - -2.000000000 = -0.000000001 +-2.000000001 - -2.000000001 = +0.000000000 +-2.000000001 - -2.000000002 = +0.000000001 +======== +-2.000000002 - 0.000000000 = -2.000000002 +-2.000000002 - 0.000000001 = -2.000000003 +-2.000000002 - 0.000000002 = -2.000000004 +-2.000000002 - 1.000000000 = -3.000000002 +-2.000000002 - 1.000000001 = -3.000000003 +-2.000000002 - 1.000000002 = -3.000000004 +-2.000000002 - 2.000000000 = -4.000000002 +-2.000000002 - 2.000000001 = -4.000000003 +-2.000000002 - 2.000000002 = -4.000000004 +==== +-2.000000002 - -0.000000001 = -2.000000001 +-2.000000002 - -0.000000002 = -2.000000000 +-2.000000002 - -1.000000000 = -1.000000002 +-2.000000002 - -1.000000001 = -1.000000001 +-2.000000002 - -1.000000002 = -1.000000000 +-2.000000002 - -2.000000000 = -0.000000002 +-2.000000002 - -2.000000001 = -0.000000001 +-2.000000002 - -2.000000002 = +0.000000000 diff --git a/ext/date/tests/time/duration/methods/sub_32.phpt b/ext/date/tests/time/duration/methods/sub_32.phpt new file mode 100644 index 000000000000..298b2bfe4953 --- /dev/null +++ b/ext/date/tests/time/duration/methods/sub_32.phpt @@ -0,0 +1,23 @@ +--TEST-- +Time\Duration::sub() (32 bit variation) +--SKIPIF-- + +--FILE-- +negate(); +$b = Time\Duration::fromSeconds(2_147_483_647, 999999999); + +try { + $a->sub($b); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Time\TimeException: The maximum representable range is 2_147_483_647 seconds (roughly 68 years) diff --git a/ext/date/tests/time/duration/methods/sub_64.phpt b/ext/date/tests/time/duration/methods/sub_64.phpt new file mode 100644 index 000000000000..c8f8fac503bf --- /dev/null +++ b/ext/date/tests/time/duration/methods/sub_64.phpt @@ -0,0 +1,23 @@ +--TEST-- +Time\Duration::sub() (64 bit variation) +--SKIPIF-- + +--FILE-- +negate(); +$b = Time\Duration::fromSeconds(9_223_372_035, 999999999); + +try { + $a->sub($b); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Time\TimeException: The maximum representable range is 9_223_372_035 seconds (roughly 292 years) diff --git a/ext/date/tests/time/duration/new.phpt b/ext/date/tests/time/duration/new.phpt new file mode 100644 index 000000000000..312752374e73 --- /dev/null +++ b/ext/date/tests/time/duration/new.phpt @@ -0,0 +1,30 @@ +--TEST-- +Time\Duration: new +--FILE-- +getMessage(), PHP_EOL; +} + +try { + (new ReflectionClass(Time\Duration::class))->newInstance(); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +try { + (new ReflectionClass(Time\Duration::class))->newInstanceWithoutConstructor(); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Error: Call to private Time\Duration::__construct() from global scope +ReflectionException: Access to non-public constructor of class Time\Duration +ReflectionException: Class Time\Duration is an internal class marked as final that cannot be instantiated without invoking its constructor diff --git a/ext/date/time.stub.php b/ext/date/time.stub.php new file mode 100644 index 000000000000..b9d0a01b39d6 --- /dev/null +++ b/ext/date/time.stub.php @@ -0,0 +1,80 @@ +. | + | | + | SPDX-License-Identifier: BSD-3-Clause | + +----------------------------------------------------------------------+ + | Authors: Derick Rethans | + | Tim Düsterhus | + +----------------------------------------------------------------------+ + */ + +#include "php.h" +#include "Zend/zend_exceptions.h" + +#include "php_date.h" +#include "php_time.h" + +#define NANOS_IN_SEC 1000000000 +#define NANOS_IN_MICRO 1000 +#define MICROS_IN_SEC 1000000 +#define NANOS_IN_MILLI 1000000 +#define MILLIS_IN_SEC 1000 + +ZEND_STATIC_ASSERT(NANOS_IN_MICRO * MICROS_IN_SEC == NANOS_IN_SEC, ""); +ZEND_STATIC_ASSERT(NANOS_IN_MILLI * MILLIS_IN_SEC == NANOS_IN_SEC, ""); + +#define Z_PARAM_ULONG(l) { \ + zend_long __l; \ + Z_PARAM_LONG(__l); \ + if (__l < 0) { \ + zend_argument_value_error(_i, "must be greater than or equal to 0"); \ + _error_code = ZPP_ERROR_FAILURE; \ + break; \ + } \ + l = __l; \ + } + +ZEND_COLD static void throw_out_of_range_exception(void) +{ +#if SIZEOF_ZEND_LONG != 4 + zend_throw_exception(php_date_ce_time_timeexception, "The maximum representable range is 9_223_372_035 seconds (roughly 292 years)", 0); +#else + zend_throw_exception(php_date_ce_time_timeexception, "The maximum representable range is 2_147_483_647 seconds (roughly 68 years)", 0); +#endif +} + +ZEND_COLD static void throw_timelib_error(int error) +{ + switch (error) { + case TIMELIB_ERROR_SECONDS_OUT_OF_RANGE: + throw_out_of_range_exception(); + break; + case TIMELIB_ERROR_DIVISION_BY_ZERO: + zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Division by zero"); + break; + case TIMELIB_ERROR_ISO8601_DURATION_PARSE_FAILURE: + case TIMELIB_ERROR_DURATION_MISSING_PERIOD: + case TIMELIB_ERROR_DURATION_ONLY_PERIOD_ALLOWED: + case TIMELIB_ERROR_DURATION_DAYS_FOUND: + zend_throw_exception(php_date_ce_time_timeexception, timelib_get_error_message(error), 0); + break; + default: + /* This should be unreachable in practice. */ + zend_throw_exception_ex(php_date_ce_time_timeexception, 0, "Failed to create a Time\\Duration: %s", timelib_get_error_message(error)); + break; + } +} + +static inline php_date_time_duration *create_duration_shell(zval *target) +{ + object_init_ex(target, php_date_ce_time_duration); + + return Z_DATE_TIME_DURATION_P(target); +} + +ZEND_ATTRIBUTE_NODISCARD static inline zend_result sync_properties(php_date_time_duration *object) +{ + if ( + /* Check if the duration would overflow the $seconds property. */ + object->duration.seconds > ((uint64_t)ZEND_LONG_MAX) + /* This constraint is an explicit part of PHP's API. While it is currently also + * enforced by timelib, this might change in a future version of timelib, thus + * we also enforce it manually. */ + || object->duration.seconds > UINT64_C(9223372035) + ) { + throw_out_of_range_exception(); + return FAILURE; + } + + ZEND_ASSERT(Z_ISUNDEF_P(OBJ_PROP_NUM(&object->std, 0))); + ZEND_ASSERT(Z_ISUNDEF_P(OBJ_PROP_NUM(&object->std, 1))); + ZEND_ASSERT(Z_ISUNDEF_P(OBJ_PROP_NUM(&object->std, 2))); + + ZVAL_LONG(OBJ_PROP_NUM(&object->std, 0), object->duration.seconds); + ZVAL_LONG(OBJ_PROP_NUM(&object->std, 1), object->duration.nanoseconds); + ZVAL_BOOL(OBJ_PROP_NUM(&object->std, 2), object->duration.negative); + + return SUCCESS; +} + +ZEND_ATTRIBUTE_NODISCARD static zend_result create_duration(zval *target, zend_ulong seconds, zend_ulong nanoseconds) +{ + ZEND_ASSERT(nanoseconds < NANOS_IN_SEC); + + if (EXPECTED(DATEG(duration_cache))) { + php_date_time_duration *cached = php_date_time_duration_from_obj(DATEG(duration_cache)); + ZEND_ASSERT(!cached->duration.negative); + + if (cached->duration.seconds == seconds && cached->duration.nanoseconds == nanoseconds) { + ZVAL_OBJ_COPY(target, &cached->std); + return SUCCESS; + } + } + + php_date_time_duration *obj = create_duration_shell(target); + + int error = timelib_duration_ctor_static(&obj->duration, seconds, nanoseconds, /* negative */ false); + if (error != TIMELIB_ERROR_NO_ERROR) { + throw_timelib_error(error); + return FAILURE; + } + + if (sync_properties(obj) == FAILURE) { + return FAILURE; + } + + if (DATEG(duration_cache)) { + zend_object_release(DATEG(duration_cache)); + } + GC_ADDREF(&obj->std); + DATEG(duration_cache) = &obj->std; + + return SUCCESS; +} + +PHP_METHOD(Time_Duration, __construct) +{ +} + +PHP_METHOD(Time_Duration, fromSeconds) +{ + zend_ulong seconds; + zend_ulong nanoseconds = 0; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ULONG(seconds); + Z_PARAM_OPTIONAL; + Z_PARAM_ULONG(nanoseconds); + ZEND_PARSE_PARAMETERS_END(); + + if (nanoseconds >= NANOS_IN_SEC) { + zend_argument_value_error(2, "must be less than 1_000_000_000"); + RETURN_THROWS(); + } + + if (create_duration(return_value, seconds, nanoseconds) == FAILURE) { + RETURN_THROWS(); + } +} + +PHP_METHOD(Time_Duration, fromNanoseconds) +{ + zend_ulong nanoseconds; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ULONG(nanoseconds); + ZEND_PARSE_PARAMETERS_END(); + + zend_ulong seconds = nanoseconds / NANOS_IN_SEC; + nanoseconds %= NANOS_IN_SEC; + + if (create_duration(return_value, seconds, nanoseconds) == FAILURE) { + RETURN_THROWS(); + } +} + +PHP_METHOD(Time_Duration, fromMicroseconds) +{ + zend_ulong microseconds; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ULONG(microseconds); + ZEND_PARSE_PARAMETERS_END(); + + zend_ulong seconds = microseconds / MICROS_IN_SEC; + zend_ulong nanoseconds = (microseconds % MICROS_IN_SEC) * NANOS_IN_MICRO; + + if (create_duration(return_value, seconds, nanoseconds) == FAILURE) { + RETURN_THROWS(); + } +} + +PHP_METHOD(Time_Duration, fromMilliseconds) +{ + zend_ulong milliseconds; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ULONG(milliseconds); + ZEND_PARSE_PARAMETERS_END(); + + zend_ulong seconds = milliseconds / MILLIS_IN_SEC; + zend_ulong nanoseconds = (milliseconds % MILLIS_IN_SEC) * NANOS_IN_MILLI; + + if (create_duration(return_value, seconds, nanoseconds) == FAILURE) { + RETURN_THROWS(); + } +} + +PHP_METHOD(Time_Duration, fromMinutes) +{ + zend_ulong minutes; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ULONG(minutes); + ZEND_PARSE_PARAMETERS_END(); + + if (minutes > (ZEND_ULONG_MAX / 60)) { + throw_out_of_range_exception(); + RETURN_THROWS(); + } + + if (create_duration(return_value, minutes * 60, /* nanoseconds */ 0) == FAILURE) { + RETURN_THROWS(); + } +} + +PHP_METHOD(Time_Duration, fromHours) +{ + zend_ulong hours; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ULONG(hours); + ZEND_PARSE_PARAMETERS_END(); + + if (hours > (ZEND_ULONG_MAX / 3600)) { + throw_out_of_range_exception(); + RETURN_THROWS(); + } + + if (create_duration(return_value, hours * 3600, /* nanoseconds */ 0) == FAILURE) { + RETURN_THROWS(); + } +} + +PHP_METHOD(Time_Duration, fromIso8601DurationString) +{ + zend_string *specification; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR(specification); + ZEND_PARSE_PARAMETERS_END(); + + int error; + timelib_duration *d = timelib_duration_create_from_iso8601string(ZSTR_VAL(specification), &error); + if (error != TIMELIB_ERROR_NO_ERROR) { + throw_timelib_error(error); + RETURN_THROWS(); + } + + php_date_time_duration *new = create_duration_shell(return_value); + new->duration = *d; + timelib_duration_dtor(d); + + if (sync_properties(new) == FAILURE) { + RETURN_THROWS(); + } +} + +PHP_METHOD(Time_Duration, negate) +{ + const php_date_time_duration *original = Z_DATE_TIME_DURATION_P(ZEND_THIS); + + ZEND_PARSE_PARAMETERS_NONE(); + + php_date_time_duration *new = create_duration_shell(return_value); + + int error = timelib_duration_negate_static(&new->duration, &original->duration); + if (error != TIMELIB_ERROR_NO_ERROR) { + throw_timelib_error(error); + RETURN_THROWS(); + } + + if (sync_properties(new) == FAILURE) { + RETURN_THROWS(); + } +} + +PHP_METHOD(Time_Duration, absolute) +{ + const php_date_time_duration *original = Z_DATE_TIME_DURATION_P(ZEND_THIS); + + ZEND_PARSE_PARAMETERS_NONE(); + + if (!original->duration.negative) { + RETURN_COPY(ZEND_THIS); + } + + if (create_duration(return_value, original->duration.seconds, original->duration.nanoseconds) == FAILURE) { + RETURN_THROWS(); + } +} + +PHP_METHOD(Time_Duration, add) +{ + const php_date_time_duration *original = Z_DATE_TIME_DURATION_P(ZEND_THIS); + + const php_date_time_duration *additional; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_DATE_TIME_DURATION(additional); + ZEND_PARSE_PARAMETERS_END(); + + php_date_time_duration *new = create_duration_shell(return_value); + + int error = timelib_duration_add_static(&new->duration, &original->duration, &additional->duration); + if (error != TIMELIB_ERROR_NO_ERROR) { + throw_timelib_error(error); + RETURN_THROWS(); + } + + if (sync_properties(new) == FAILURE) { + RETURN_THROWS(); + } +} + +PHP_METHOD(Time_Duration, sub) +{ + const php_date_time_duration *original = Z_DATE_TIME_DURATION_P(ZEND_THIS); + + const php_date_time_duration *minus; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_DATE_TIME_DURATION(minus); + ZEND_PARSE_PARAMETERS_END(); + + php_date_time_duration *new = create_duration_shell(return_value); + + int error = timelib_duration_sub_static(&new->duration, &original->duration, &minus->duration); + if (error != TIMELIB_ERROR_NO_ERROR) { + throw_timelib_error(error); + RETURN_THROWS(); + } + + if (sync_properties(new) == FAILURE) { + RETURN_THROWS(); + } +} + +PHP_METHOD(Time_Duration, multiplyBy) +{ + const php_date_time_duration *original = Z_DATE_TIME_DURATION_P(ZEND_THIS); + + zend_ulong factor; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ULONG(factor); + ZEND_PARSE_PARAMETERS_END(); + + php_date_time_duration *new = create_duration_shell(return_value); + + int error = timelib_duration_mul_static(&new->duration, &original->duration, factor); + if (error != TIMELIB_ERROR_NO_ERROR) { + throw_timelib_error(error); + RETURN_THROWS(); + } + + if (sync_properties(new) == FAILURE) { + RETURN_THROWS(); + } +} + +PHP_METHOD(Time_Duration, divideBy) +{ + const php_date_time_duration *original = Z_DATE_TIME_DURATION_P(ZEND_THIS); + + zend_ulong divisor; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ULONG(divisor); + ZEND_PARSE_PARAMETERS_END(); + + php_date_time_duration *new = create_duration_shell(return_value); + + int error = timelib_duration_div_static(&new->duration, &original->duration, divisor); + if (error != TIMELIB_ERROR_NO_ERROR) { + throw_timelib_error(error); + RETURN_THROWS(); + } + + if (sync_properties(new) == FAILURE) { + RETURN_THROWS(); + } +} + +PHP_METHOD(Time_Duration, compare) +{ + const php_date_time_duration *a; + const php_date_time_duration *b; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_DATE_TIME_DURATION(a); + Z_PARAM_DATE_TIME_DURATION(b); + ZEND_PARSE_PARAMETERS_END(); + + RETURN_LONG(timelib_duration_compare(&a->duration, &b->duration)); +}