Hi Derick and all,
strtotime()
may be improved.
$ php -r "echo date('Y-m-d',strtotime('00-00-00 00:00:00'));"
1999-11-30
because 00 is 2000, 00 month is -1(=12) and 00 date is -1(last date of
previous month).
This is unintuitive result at a glance.
strtotime()
handles date/time edge cases and produces reasonable timestamp
in some cases.
$ php -r "echo date('Y-m-d H:i:s',strtotime('00-01-01 24:00:00'));"
2000-01-02 00:00:00
$ php -r "echo date('Y-m-d H:i:s',strtotime('03-02-29 00:00:00'));"
2003-03-01 00:00:00
$ php -r "echo date('Y-m-d H:i:s',strtotime('03-02-28 23:59:60'));"
2003-03-01 00:00:00
It returns FALSE
for larger values exceeds edge cases. For example,
$ php -r "var_dump(strtotime('03-02-32 00:00:00'));"
bool(false)
Somehow it does not accept 13 month while it is edge case.
$ php -r "var_dump(strtotime('03-13-30 00:00:00'));"
bool(false)
It does not accept day 32 while it accepts 2/31.
$ php -r "var_dump(strtotime('03-01-32 00:00:00'));"
bool(false)
$ php -r "var_dump(strtotime('03-02-31 00:00:00'));"
int(1046617200)
25 hour/60 minutes is invalid also.
$ php -r "var_dump(strtotime('03-02-31 00:60:00'));"
bool(false)
$ php -r "var_dump(strtotime('03-02-31 25:00:00'));"
bool(false)
It seems edge case handling is inconsistent.
How about make strtotime()
- Accept all edge cases by default.
- Add $strict flag as 2nd parameter and reject any invalid date/time.
(Do not allow leap second also? Some system may create 60th second)
Alternatively, we may be strict
- Disallow all edge cases by default.
(There may be problem with leap second)
Any comments?
Reference:
https://bugs.php.net/bug.php?id=45647
--
Yasuo Ohgaki
yohgaki@ohgaki.net
Hi,
Currently, it works as follows by design:
-
the parser, allows for each unit (year, month, day, hour, minute,
second) the full range of values. For a year that's just 4 digits, for
a month that's 0-12, day is 0-31 and for hour and minute it's 0-59. -
60 is allowed for seconds, as sometimes date strings with that
leapsecond do show up. But PHP implements Unix time where "60" is not
a valid second number and hence it overflows. There is some more
background information at http://drck.me/leapsec-6ye -
strtotime()
returns false if any number is outside of the ranges, and
new DateTime() throws an exception. -
the parser is dumb, and doesn't do any checks to make it faster (and
more generic) -
but, there is an additional check if you pass in an invalid date
(like your suggested $strict):$ php -r '$res = date_parse("2015-09-31"); var_dump($res["warnings"]);'
array(1) {
[11] =>
string(27) "The parsed date was invalid"
} -
It is already possible to handle the edge cases, but then you need to
supply the right format. Otherwise there are too many possible
confusing and unintuitive results coming out of the parser:php -r '$res = date_create_from_format("Y-m-d", "2015-09-34"); var_dump($res);'
class DateTime#1 (3) {
public $date =>
string(26) "2015-10-04 17:24:43.000000"
public $timezone_type =>
int(3)
public $timezone =>
string(13) "Europe/London"
} -
We can't add a second argument to
strtotime()
, because it already
exists. -
Having a "strict" option to
strtotime()
does also not work, as that
would mean two distinct parsing routines.
With all those concerns, as well as functionality to handle edge cases
in place, I do not think we should change anything.
cheers,
Derick
Hi Derick and all,
strtotime()
may be improved.$ php -r "echo date('Y-m-d',strtotime('00-00-00 00:00:00'));"
1999-11-30
because 00 is 2000, 00 month is -1(=12) and 00 date is -1(last date of
previous month).
This is unintuitive result at a glance.
strtotime()
handles date/time edge cases and produces reasonable timestamp
in some cases.$ php -r "echo date('Y-m-d H:i:s',strtotime('00-01-01 24:00:00'));"
2000-01-02 00:00:00
$ php -r "echo date('Y-m-d H:i:s',strtotime('03-02-29 00:00:00'));"
2003-03-01 00:00:00
$ php -r "echo date('Y-m-d H:i:s',strtotime('03-02-28 23:59:60'));"
2003-03-01 00:00:00It returns
FALSE
for larger values exceeds edge cases. For example,
$ php -r "var_dump(strtotime('03-02-32 00:00:00'));"
bool(false)Somehow it does not accept 13 month while it is edge case.
$ php -r "var_dump(strtotime('03-13-30 00:00:00'));"
bool(false)
It does not accept day 32 while it accepts 2/31.
$ php -r "var_dump(strtotime('03-01-32 00:00:00'));"
bool(false)
$ php -r "var_dump(strtotime('03-02-31 00:00:00'));"
int(1046617200)
25 hour/60 minutes is invalid also.
$ php -r "var_dump(strtotime('03-02-31 00:60:00'));"
bool(false)
$ php -r "var_dump(strtotime('03-02-31 25:00:00'));"
bool(false)It seems edge case handling is inconsistent.
How about make
strtotime()
- Accept all edge cases by default.
- Add $strict flag as 2nd parameter and reject any invalid date/time.
(Do not allow leap second also? Some system may create 60th second)Alternatively, we may be strict
- Disallow all edge cases by default.
(There may be problem with leap second)Any comments?
Reference:
https://bugs.php.net/bug.php?id=45647--
Yasuo Ohgaki
yohgaki@ohgaki.net
--
http://derickrethans.nl | http://xdebug.org
Like Xdebug? Consider a donation: http://xdebug.org/donate.php
twitter: @derickr and @xdebug
Posted with an email client that doesn't mangle email: alpine
Hi Derick,
Currently, it works as follows by design:
the parser, allows for each unit (year, month, day, hour, minute,
second) the full range of values. For a year that's just 4 digits, for
a month that's 0-12, day is 0-31 and for hour and minute it's 0-59.60 is allowed for seconds, as sometimes date strings with that
leapsecond do show up. But PHP implements Unix time where "60" is not
a valid second number and hence it overflows. There is some more
background information at http://drck.me/leapsec-6ye
strtotime()
returns false if any number is outside of the ranges, and
new DateTime() throws an exception.the parser is dumb, and doesn't do any checks to make it faster (and
more generic)but, there is an additional check if you pass in an invalid date
(like your suggested $strict):$ php -r '$res = date_parse("2015-09-31"); var_dump($res["warnings"]);'
array(1) {
[11] =>
string(27) "The parsed date was invalid"
}It is already possible to handle the edge cases, but then you need to
supply the right format. Otherwise there are too many possible
confusing and unintuitive results coming out of the parser:php -r '$res = date_create_from_format("Y-m-d", "2015-09-34"); var_dump($res);'
class DateTime#1 (3) {
public $date =>
string(26) "2015-10-04 17:24:43.000000"
public $timezone_type =>
int(3)
public $timezone =>
string(13) "Europe/London"
}We can't add a second argument to
strtotime()
, because it already
exists.Having a "strict" option to
strtotime()
does also not work, as that
would mean two distinct parsing routines.With all those concerns, as well as functionality to handle edge cases
in place, I do not think we should change anything.
Thank you for detailed explanation.
I'm OK with current design/API. How about add documentation for more precise
date/time parsing and handling to strtotime()
manual page?
One concern is "0000-00-00" date. MySQL uses it as invalid date and strtotime()
produces non intuitive result. It should be added to the document also.
I made a bug report to track this.
https://bugs.php.net/bug.php?id=70463
Regards,
--
Yasuo Ohgaki
yohgaki@ohgaki.net
Hi Derick,
Currently, it works as follows by design:
the parser, allows for each unit (year, month, day, hour, minute,
second) the full range of values. For a year that's just 4 digits, for
a month that's 0-12, day is 0-31 and for hour and minute it's 0-59.60 is allowed for seconds, as sometimes date strings with that
leapsecond do show up. But PHP implements Unix time where "60" is not
a valid second number and hence it overflows. There is some more
background information at http://drck.me/leapsec-6ye
strtotime()
returns false if any number is outside of the ranges, and
new DateTime() throws an exception.the parser is dumb, and doesn't do any checks to make it faster (and
more generic)but, there is an additional check if you pass in an invalid date
(like your suggested $strict):$ php -r '$res = date_parse("2015-09-31"); var_dump($res["warnings"]);'
array(1) {
[11] =>
string(27) "The parsed date was invalid"
}It is already possible to handle the edge cases, but then you need to
supply the right format. Otherwise there are too many possible
confusing and unintuitive results coming out of the parser:php -r '$res = date_create_from_format("Y-m-d", "2015-09-34"); var_dump($res);'
class DateTime#1 (3) {
public $date =>
string(26) "2015-10-04 17:24:43.000000"
public $timezone_type =>
int(3)
public $timezone =>
string(13) "Europe/London"
}We can't add a second argument to
strtotime()
, because it already
exists.Having a "strict" option to
strtotime()
does also not work, as that
would mean two distinct parsing routines.With all those concerns, as well as functionality to handle edge cases
in place, I do not think we should change anything.Thank you for detailed explanation.
I'm OK with current design/API. How about add documentation for more precise
date/time parsing and handling tostrtotime()
manual page?
There is a whole section at:
http://docs.php.net/manual/en/datetime.formats.php
Although it doesn't seem to get the 60 for seconds right.
I made a bug report to track this.
https://bugs.php.net/bug.php?id=70463
Ok, cool.
cheers,
Derick