Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ PHP NEWS

- Date:
. Update timelib to 2026.02. (Derick, timwolla)
. Added Time\Duration. (timwolla, Derick)

- GMP:
. Added optional $definitely_prime output parameter to gmp_prevprime().
Expand Down
10 changes: 10 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,10 @@ PHP 8.6 UPGRADE NOTES
offset and origin, and must return one of CURL_SEEKFUNC_OK,
CURL_SEEKFUNC_FAIL or CURL_SEEKFUNC_CANTSEEK.

- Date:
. Added a new Time\Duration class.
RFC: https://wiki.php.net/rfc/duration_class

- Fileinfo:
. finfo_file() now works with remote streams.

Expand Down Expand Up @@ -553,6 +557,12 @@ PHP 8.6 UPGRADE NOTES
7. New Classes and Interfaces
========================================

- Date:
. Time\Duration
RFC: https://wiki.php.net/rfc/duration_class
. Time\TimeException
RFC: https://wiki.php.net/rfc/duration_class

- Intl:
. IntlNumberRangeFormatter

Expand Down
2 changes: 1 addition & 1 deletion ext/date/config.w32
Original file line number Diff line number Diff line change
@@ -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");

Expand Down
2 changes: 1 addition & 1 deletion ext/date/config0.m4
Original file line number Diff line number Diff line change
Expand Up @@ -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])

Expand Down
7 changes: 7 additions & 0 deletions ext/date/php_date.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
}
/* }}} */

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions ext/date/php_date.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
65 changes: 65 additions & 0 deletions ext/date/php_time.c
Original file line number Diff line number Diff line change
@@ -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 <https://www.php.net/license/>. |
| |
| SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Derick Rethans <derick@derickrethans.nl> |
| Tim Düsterhus <timwolla@php.net> |
+----------------------------------------------------------------------+
*/

#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);
Comment thread
TimWolla marked this conversation as resolved.

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;
}
48 changes: 48 additions & 0 deletions ext/date/php_time.h
Original file line number Diff line number Diff line change
@@ -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 <https://www.php.net/license/>. |
| |
| SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Derick Rethans <derick@derickrethans.nl> |
| Tim Düsterhus <timwolla@php.net> |
+----------------------------------------------------------------------+
*/

#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;
Comment thread
derickr marked this conversation as resolved.

PHP_MINIT_FUNCTION(date_time);

#endif /* PHP_DATE_TIME_H */
24 changes: 24 additions & 0 deletions ext/date/tests/time/duration/clone.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
--TEST--
Time\Duration: clone
--FILE--
<?php

require __DIR__ . '/helper.inc';

function fc(Time\Duration $d): string {
return f(clone($d));
}

echo fc(Time\Duration::fromSeconds(0, 0)), PHP_EOL;
echo fc(Time\Duration::fromSeconds(0, 1)), PHP_EOL;
echo fc(Time\Duration::fromSeconds(1, 1)), PHP_EOL;
echo fc(Time\Duration::fromSeconds(0, 1)->negate()), PHP_EOL;
echo fc(Time\Duration::fromSeconds(1, 1)->negate()), PHP_EOL;

?>
--EXPECT--
+0.000000000
+0.000000001
+1.000000001
-0.000000001
-1.000000001
32 changes: 32 additions & 0 deletions ext/date/tests/time/duration/helper.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

function f(Time\Duration $d, bool $pad = true, bool $plus_sign = true): string {
$result = sprintf("%s%d.%09d", ($d->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 {
$negated = array_map(negate(...), $d);

/* Filter out values that were not successfully negated (i.e. 0-values). */
return array_filter($negated, is_negative(...));
}
29 changes: 29 additions & 0 deletions ext/date/tests/time/duration/methods/absolute.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
--TEST--
Time\Duration::absolute()
--FILE--
<?php

require __DIR__ . '/../helper.inc';

echo f(Time\Duration::fromSeconds(0, 0)->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
Loading
Loading