Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:88116 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 85821 invoked from network); 8 Sep 2015 16:31:29 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 8 Sep 2015 16:31:29 -0000 Authentication-Results: pb1.pair.com header.from=derick@php.net; sender-id=unknown Authentication-Results: pb1.pair.com smtp.mail=derick@php.net; spf=unknown; sender-id=unknown Received-SPF: unknown (pb1.pair.com: domain php.net does not designate 82.113.146.227 as permitted sender) X-PHP-List-Original-Sender: derick@php.net X-Host-Fingerprint: 82.113.146.227 xdebug.org Linux 2.6 Received: from [82.113.146.227] ([82.113.146.227:37840] helo=xdebug.org) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id E3/E0-10366-D5D0FE55 for ; Tue, 08 Sep 2015 12:31:27 -0400 Received: from localhost (localhost [IPv6:::1]) by xdebug.org (Postfix) with ESMTPS id 34B0D10C009; Tue, 8 Sep 2015 17:31:21 +0100 (BST) Date: Tue, 8 Sep 2015 17:31:14 +0100 (BST) X-X-Sender: derick@whisky.home.derickrethans.nl To: Yasuo Ohgaki cc: "internals@lists.php.net" In-Reply-To: Message-ID: References: User-Agent: Alpine 2.20 (DEB 67 2015-01-07) MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Subject: Re: Invalid date/time handling - strtotime() From: derick@php.net (Derick Rethans) 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 On Tue, 8 Sep 2015, Yasuo Ohgaki wrote: > 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 > -- 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