Skip to content

Commit c7cc823

Browse files
committed
DateRangeError + static return type
1 parent 9df735e commit c7cc823

File tree

5 files changed

+115
-55
lines changed

5 files changed

+115
-55
lines changed

Zend/Optimizer/zend_func_infos.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ static const func_info_t func_infos[] = {
5454
F1("date_create_immutable", MAY_BE_OBJECT|MAY_BE_FALSE),
5555
F1("date_create_from_format", MAY_BE_OBJECT|MAY_BE_FALSE),
5656
F1("date_create_immutable_from_format", MAY_BE_OBJECT|MAY_BE_FALSE),
57-
F1("date_create_from_timestamp", MAY_BE_OBJECT|MAY_BE_FALSE),
58-
F1("date_create_immutable_from_timestamp", MAY_BE_OBJECT|MAY_BE_FALSE),
57+
F1("date_create_from_timestamp", MAY_BE_OBJECT),
58+
F1("date_create_immutable_from_timestamp", MAY_BE_OBJECT),
5959
F1("date_parse", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY),
6060
F1("date_parse_from_format", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY),
6161
F1("date_get_last_errors", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_FALSE),

ext/date/php_date.c

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2512,14 +2512,21 @@ PHPAPI void php_date_initialize_from_ts_long(php_date_obj *dateobj, zend_long se
25122512

25132513
PHPAPI bool php_date_initialize_from_ts_double(php_date_obj *dateobj, double ts) /* {{{ */
25142514
{
2515+
double sec_dval = trunc(ts);
25152516
zend_long sec;
25162517
int usec;
25172518

2518-
if (UNEXPECTED(isnan(ts) || !ZEND_DOUBLE_FITS_LONG(ts))) {
2519-
return 0;
2519+
if (UNEXPECTED(isnan(sec_dval)
2520+
|| sec_dval >= (double)TIMELIB_LONG_MAX
2521+
|| sec_dval < (double)TIMELIB_LONG_MIN
2522+
)) {
2523+
zend_throw_error(date_ce_date_range_error,
2524+
"Seconds must be a finite number between "TIMELIB_LONG_FMT" and "TIMELIB_LONG_FMT", %g given",
2525+
TIMELIB_LONG_MIN, TIMELIB_LONG_MAX, sec_dval);
2526+
return false;
25202527
}
25212528

2522-
sec = (zend_long)ts;
2529+
sec = (zend_long)sec_dval;
25232530
usec = (int)(fmod(ts, 1) * 1000000);
25242531

25252532
if (UNEXPECTED(usec < 0)) {
@@ -2529,7 +2536,7 @@ PHPAPI bool php_date_initialize_from_ts_double(php_date_obj *dateobj, double ts)
25292536

25302537
php_date_initialize_from_ts_long(dateobj, sec, usec);
25312538

2532-
return 1;
2539+
return true;
25332540
} /* }}} */
25342541

25352542
/* {{{ Returns new DateTime object */
@@ -2621,60 +2628,66 @@ PHP_FUNCTION(date_create_immutable_from_format)
26212628
/* {{{ Returns new DateTime object from given unix timetamp */
26222629
PHP_FUNCTION(date_create_from_timestamp)
26232630
{
2624-
php_date_obj *dateobj;
26252631
zval *value;
2632+
zval new_object;
2633+
php_date_obj *new_dateobj;
26262634

26272635
ZEND_PARSE_PARAMETERS_START(1, 1)
26282636
Z_PARAM_NUMBER(value)
26292637
ZEND_PARSE_PARAMETERS_END();
26302638

2631-
php_date_instantiate(date_ce_date, return_value);
2632-
dateobj = Z_PHPDATE_P(return_value);
2639+
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date, &new_object);
2640+
new_dateobj = Z_PHPDATE_P(&new_object);
26332641

26342642
switch (Z_TYPE_P(value)) {
26352643
case IS_LONG:
2636-
php_date_initialize_from_ts_long(dateobj, Z_LVAL_P(value), 0);
2644+
php_date_initialize_from_ts_long(new_dateobj, Z_LVAL_P(value), 0);
26372645
break;
26382646

26392647
case IS_DOUBLE:
2640-
if (!php_date_initialize_from_ts_double(dateobj, Z_DVAL_P(value))) {
2641-
zval_ptr_dtor(return_value);
2642-
RETURN_FALSE;
2648+
if (!php_date_initialize_from_ts_double(new_dateobj, Z_DVAL_P(value))) {
2649+
zval_ptr_dtor(&new_object);
2650+
RETURN_THROWS();
26432651
}
26442652
break;
26452653

26462654
EMPTY_SWITCH_DEFAULT_CASE();
26472655
}
2656+
2657+
RETURN_OBJ(Z_OBJ(new_object));
26482658
}
26492659
/* }}} */
26502660

26512661
/* {{{ Returns new DateTimeImmutable object from given unix timestamp */
26522662
PHP_FUNCTION(date_create_immutable_from_timestamp)
26532663
{
2654-
php_date_obj *dateobj;
26552664
zval *value;
2665+
zval new_object;
2666+
php_date_obj *new_dateobj;
26562667

26572668
ZEND_PARSE_PARAMETERS_START(1, 1)
26582669
Z_PARAM_NUMBER(value)
26592670
ZEND_PARSE_PARAMETERS_END();
26602671

2661-
php_date_instantiate(date_ce_immutable, return_value);
2662-
dateobj = Z_PHPDATE_P(return_value);
2672+
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable, &new_object);
2673+
new_dateobj = Z_PHPDATE_P(&new_object);
26632674

26642675
switch (Z_TYPE_P(value)) {
26652676
case IS_LONG:
2666-
php_date_initialize_from_ts_long(dateobj, Z_LVAL_P(value), 0);
2677+
php_date_initialize_from_ts_long(new_dateobj, Z_LVAL_P(value), 0);
26672678
break;
26682679

26692680
case IS_DOUBLE:
2670-
if (!php_date_initialize_from_ts_double(dateobj, Z_DVAL_P(value))) {
2671-
zval_ptr_dtor(return_value);
2672-
RETURN_FALSE;
2681+
if (!php_date_initialize_from_ts_double(new_dateobj, Z_DVAL_P(value))) {
2682+
zval_ptr_dtor(&new_object);
2683+
RETURN_THROWS();
26732684
}
26742685
break;
26752686

26762687
EMPTY_SWITCH_DEFAULT_CASE();
26772688
}
2689+
2690+
RETURN_OBJ(Z_OBJ(new_object));
26782691
}
26792692
/* }}} */
26802693

ext/date/php_date.stub.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,10 @@ function date_create_immutable_from_format(
160160
string $format, string $datetime, ?DateTimeZone $timezone = null): DateTimeImmutable|false {}
161161

162162
/** @refcount 1 */
163-
function date_create_from_timestamp(int|float $timestamp): DateTime|false {}
163+
function date_create_from_timestamp(int|float $timestamp): DateTime {}
164164

165165
/** @refcount 1 */
166-
function date_create_immutable_from_timestamp(int|float $timestamp): DateTimeImmutable|false {}
166+
function date_create_immutable_from_timestamp(int|float $timestamp): DateTimeImmutable {}
167167

168168
/**
169169
* @return array<string, mixed>
@@ -372,7 +372,7 @@ public static function createFromFormat(string $format, string $datetime, ?DateT
372372
* @tentative-return-type
373373
* @alias date_create_from_timestamp
374374
*/
375-
public static function createFromTimestamp(int|float $timestamp): DateTime|false {}
375+
public static function createFromTimestamp(int|float $timestamp): static {}
376376

377377
/**
378378
* @return array<string, int|array>|false
@@ -482,7 +482,7 @@ public static function createFromFormat(string $format, string $datetime, ?DateT
482482
* @tentative-return-type
483483
* @alias date_create_immutable_from_timestamp
484484
*/
485-
public static function createFromTimestamp(int|float $timestamp): DateTimeImmutable|false {}
485+
public static function createFromTimestamp(int|float $timestamp): static {}
486486

487487
/**
488488
* @return array<string, int|array>|false

ext/date/php_date_arginfo.h

Lines changed: 5 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/date/tests/createFromTimestamp.phpt

Lines changed: 73 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ date.timezone=Europe/London
55
--FILE--
66
<?php
77

8+
class MyDateTime extends DateTime {};
9+
class MyDateTimeImmutable extends DateTimeImmutable {};
10+
811
define('MAX_32BIT', 2147483647);
912
define('MIN_32BIT', -2147483648);
1013

@@ -29,16 +32,46 @@ $timestamps = array(
2932

3033
foreach ($timestamps as $ts) {
3134
echo 'date_create_from_timestamp(' . var_export($ts, true) . '): ';
32-
var_dump(date_create_from_timestamp($ts));
35+
try {
36+
var_dump(date_create_from_timestamp($ts));
37+
} catch (Throwable $e) {
38+
echo get_class($e) . ': ' . $e->getMessage() . "\n";
39+
}
3340

3441
echo 'DateTime::createFromTimestamp(' . var_export($ts, true) . '): ';
35-
var_dump(DateTime::createFromTimestamp($ts));
42+
try {
43+
var_dump(DateTime::createFromTimestamp($ts));
44+
} catch (Throwable $e) {
45+
echo get_class($e) . ': ' . $e->getMessage() . "\n";
46+
}
3647

3748
echo 'date_create_immutable_from_timestamp(' . var_export($ts, true) . '): ';
38-
var_dump(date_create_immutable_from_timestamp($ts));
49+
try {
50+
var_dump(date_create_immutable_from_timestamp($ts));
51+
} catch (Throwable $e) {
52+
echo get_class($e) . ': ' . $e->getMessage() . "\n";
53+
}
3954

4055
echo 'DateTimeImmutable::createFromTimestamp(' . var_export($ts, true) . '): ';
41-
var_dump(DateTimeImmutable::createFromTimestamp($ts));
56+
try {
57+
var_dump(DateTimeImmutable::createFromTimestamp($ts));
58+
} catch (Throwable $e) {
59+
echo get_class($e) . ': ' . $e->getMessage() . "\n";
60+
}
61+
}
62+
63+
echo 'MyDateTime::createFromTimestamp(' . var_export(0, true) . '): ';
64+
try {
65+
var_dump(MyDateTime::createFromTimestamp(0));
66+
} catch (Throwable $e) {
67+
echo get_class($e) . ': ' . $e->getMessage() . "\n";
68+
}
69+
70+
echo 'MyDateTimeImmutable::createFromTimestamp(' . var_export(0, true) . '): ';
71+
try {
72+
var_dump(MyDateTimeImmutable::createFromTimestamp(0));
73+
} catch (Throwable $e) {
74+
echo get_class($e) . ': ' . $e->getMessage() . "\n";
4275
}
4376

4477
?>
@@ -395,23 +428,39 @@ DateTimeImmutable::createFromTimestamp(-2147483648): object(DateTimeImmutable)#%
395428
["timezone"]=>
396429
string(6) "+00:00"
397430
}
398-
date_create_from_timestamp(9.223372036854776E+18): bool(false)
399-
DateTime::createFromTimestamp(9.223372036854776E+18): bool(false)
400-
date_create_immutable_from_timestamp(9.223372036854776E+18): bool(false)
401-
DateTimeImmutable::createFromTimestamp(9.223372036854776E+18): bool(false)
402-
date_create_from_timestamp(-9.223372036854778E+18): bool(false)
403-
DateTime::createFromTimestamp(-9.223372036854778E+18): bool(false)
404-
date_create_immutable_from_timestamp(-9.223372036854778E+18): bool(false)
405-
DateTimeImmutable::createFromTimestamp(-9.223372036854778E+18): bool(false)
406-
date_create_from_timestamp(NAN): bool(false)
407-
DateTime::createFromTimestamp(NAN): bool(false)
408-
date_create_immutable_from_timestamp(NAN): bool(false)
409-
DateTimeImmutable::createFromTimestamp(NAN): bool(false)
410-
date_create_from_timestamp(INF): bool(false)
411-
DateTime::createFromTimestamp(INF): bool(false)
412-
date_create_immutable_from_timestamp(INF): bool(false)
413-
DateTimeImmutable::createFromTimestamp(INF): bool(false)
414-
date_create_from_timestamp(-INF): bool(false)
415-
DateTime::createFromTimestamp(-INF): bool(false)
416-
date_create_immutable_from_timestamp(-INF): bool(false)
417-
DateTimeImmutable::createFromTimestamp(-INF): bool(false)
431+
date_create_from_timestamp(9.223372036854776E+18): DateRangeError: Seconds must be a finite number between %i and %i, 9.22337e+18 given
432+
DateTime::createFromTimestamp(9.223372036854776E+18): DateRangeError: Seconds must be a finite number between %i and %i, 9.22337e+18 given
433+
date_create_immutable_from_timestamp(9.223372036854776E+18): DateRangeError: Seconds must be a finite number between %i and %i, 9.22337e+18 given
434+
DateTimeImmutable::createFromTimestamp(9.223372036854776E+18): DateRangeError: Seconds must be a finite number between %i and %i, 9.22337e+18 given
435+
date_create_from_timestamp(-9.223372036854778E+18): DateRangeError: Seconds must be a finite number between %i and %i, -9.22337e+18 given
436+
DateTime::createFromTimestamp(-9.223372036854778E+18): DateRangeError: Seconds must be a finite number between %i and %i, -9.22337e+18 given
437+
date_create_immutable_from_timestamp(-9.223372036854778E+18): DateRangeError: Seconds must be a finite number between %i and %i, -9.22337e+18 given
438+
DateTimeImmutable::createFromTimestamp(-9.223372036854778E+18): DateRangeError: Seconds must be a finite number between %i and %i, -9.22337e+18 given
439+
date_create_from_timestamp(NAN): DateRangeError: Seconds must be a finite number between %i and %i, NAN given
440+
DateTime::createFromTimestamp(NAN): DateRangeError: Seconds must be a finite number between %i and %i, NAN given
441+
date_create_immutable_from_timestamp(NAN): DateRangeError: Seconds must be a finite number between %i and %i, NAN given
442+
DateTimeImmutable::createFromTimestamp(NAN): DateRangeError: Seconds must be a finite number between %i and %i, NAN given
443+
date_create_from_timestamp(INF): DateRangeError: Seconds must be a finite number between %i and %i, INF given
444+
DateTime::createFromTimestamp(INF): DateRangeError: Seconds must be a finite number between %i and %i, INF given
445+
date_create_immutable_from_timestamp(INF): DateRangeError: Seconds must be a finite number between %i and %i, INF given
446+
DateTimeImmutable::createFromTimestamp(INF): DateRangeError: Seconds must be a finite number between %i and %i, INF given
447+
date_create_from_timestamp(-INF): DateRangeError: Seconds must be a finite number between %i and %i, -INF given
448+
DateTime::createFromTimestamp(-INF): DateRangeError: Seconds must be a finite number between %i and %i, -INF given
449+
date_create_immutable_from_timestamp(-INF): DateRangeError: Seconds must be a finite number between %i and %i, -INF given
450+
DateTimeImmutable::createFromTimestamp(-INF): DateRangeError: Seconds must be a finite number between %i and %i, -INF given
451+
MyDateTime::createFromTimestamp(0): object(MyDateTime)#%d (3) {
452+
["date"]=>
453+
string(26) "1970-01-01 00:00:00.000000"
454+
["timezone_type"]=>
455+
int(1)
456+
["timezone"]=>
457+
string(6) "+00:00"
458+
}
459+
MyDateTimeImmutable::createFromTimestamp(0): object(MyDateTimeImmutable)#%d (3) {
460+
["date"]=>
461+
string(26) "1970-01-01 00:00:00.000000"
462+
["timezone_type"]=>
463+
int(1)
464+
["timezone"]=>
465+
string(6) "+00:00"
466+
}

0 commit comments

Comments
 (0)