ID:               48824
 User updated by:  brad at omnis dot com
 Reported By:      brad at omnis dot com
 Status:           Bogus
 Bug Type:         Date/time related
 Operating System: Linux (CentOS 5.3)
 PHP Version:      5.3.0
 New Comment:

Let me start off by saying "Calendar Math != Numeric Math".  Lets get
that clear.  Calendars are messy (i.e. 60m = 1h, 24h = 1d, leap seconds,
leap years, etc) and things don't always back out as you might wish they
would.  Your examples are EXACTLY what I would expect them to do when
asking a computer to do that type of math you've given to it to do.  You
also have to ask the question, what would a human operator expect from
adding +1 month to January 31st.  Everyone I have spoken with agrees
that it should be February and not March.

"DateInterval is used for iteration." In your opinion.  Last I checked
PHP is used by more persons than just yourself.  If this language were
only used by PHP Devs then we would not be having this discussion.  For
your example of the usage of DateInterval I think it's great, but that
does not mean that my usage is somehow invalid.

My first inclination when I saw the new functions, was "Great!  I hope
these new functions are calendar based date math in PHP instead of
numeric math based."

My "precision math" comment should have said "accurate math", bad
choice of words on my part, but the point is still valid.  I would
challenge you to find a single person, who doesn't have a 
predisposition to UNIX date semantics, who would agree that adding 1
month to January 31st should result in a date in March.

Further, have you or any other PHP dev written PHP code that used
strtotime("+1 month") where it would be acceptable to have January 31st
+ 1 month = March?  Because after lots of thought, I can not come up
with a single example of where I would find that acceptable.

I don't see what the opposition to having another way of doing the date
calculation is.  As it is right now, I guarantee you that standard php
date functions are inadequate for use in any sort of billing/accounting
systems without additional modification to handle their shortcomings.

I am obviously not the only person to request this functionality since
there are numerous bug reports on the issue.  What is the opposition to
giving those users the choice of how to deal with date math?

Here are examples of how other scripting languages that compete with
PHP do it (hint they ALL have ways to achieve the results I expect):

::::::::::::::
java: datetest.java
::::::::::::::
import java.util.Date;
import java.util.Calendar;
import java.text.SimpleDateFormat;
import java.util.*;


class datetest { 
        public static void main(String args[]) { 

                SimpleDateFormat formatter = new SimpleDateFormat("E
yyyy.MM.dd 'at' hh:mm:ss a zzz");

                Calendar rightNow = Calendar.getInstance();
                rightNow.set(2009,0,31);

                System.out.println(
formatter.format(rightNow.getTime())); 

                rightNow.add(Calendar.MONTH,+ 1);
                
               
System.out.println(formatter.format(rightNow.getTime())); 

        } 
}
::::::::::::::
perl: datetest.pl
::::::::::::::
use DateTime;
use DateTime::Duration;

my $date = DateTime->new(
  year      =>    2009,
  month     =>      1,
  day       =>      31,
  locale    => 'en_US',
);

my $duration = DateTime::Duration->new(
  months        =>          1,
  end_of_month  => 'preserve',
);

$date->add( $duration );  # One month more
print $date->mdy('/');    # And show it


::::::::::::::
python: datetest.py
::::::::::::::
from datetime import *; from dateutil.relativedelta import *
import calendar

print date(2009,1,31)+relativedelta(months=+1)

::::::::::::::
ruby: datetest.rb
::::::::::::::
require 'date'
d1 = Date.new(y=2009,m=1,d=31)
puts d1
d2 = (d1 >> 1)
puts d2


Previous Comments:
------------------------------------------------------------------------

[2009-08-07 01:13:01] ras...@php.net

DateInterval is used for iteration.  For stuff like this:

$db = new DateTime('2008-12-31');
$de = new DateTime('2009-12-31');
$di = DateInterval::createFromDateString('third tuesday of next
month');
$dp = new DatePeriod($db, $di, $de, DatePeriod::EXCLUDE_START_DATE);
foreach($dp as $dt) {
   echo $dt->format("F jS\n") . "<br>\n";
}

I also disagree with your suggestion that "calendar math" is "precision
math calculations".  The strtotime approach is actually the precise
approach since you never have inconsistencies like this:

mysql> SELECT DATE_ADD('2009-01-31 23:59:59',INTERVAL 1 MONTH);
+--------------------------------------------------+
| DATE_ADD('2009-01-31 23:59:59',INTERVAL 1 MONTH) |
+--------------------------------------------------+
| 2009-02-28 23:59:59                              | 
+--------------------------------------------------+

mysql> SELECT DATE_SUB('2009-02-28 23:59:59',INTERVAL 1 MONTH);
+--------------------------------------------------+
| DATE_SUB('2009-02-28 23:59:59',INTERVAL 1 MONTH) |
+--------------------------------------------------+
| 2009-01-28 23:59:59                              | 
+--------------------------------------------------+

So, you essentially have 
$a + month = $b
$b - month != $a

Or have 2 times 24-hours apart map to the same exact timestamp when you
add a month:

mysql> SELECT DATE_ADD('2009-01-31 23:59:59',INTERVAL 1 MONTH);
+--------------------------------------------------+
| DATE_ADD('2009-01-31 23:59:59',INTERVAL 1 MONTH) |
+--------------------------------------------------+
| 2009-02-28 23:59:59                              | 
+--------------------------------------------------+

mysql> SELECT DATE_ADD('2009-01-30 23:59:59',INTERVAL 1 MONTH);
+--------------------------------------------------+
| DATE_ADD('2009-01-30 23:59:59',INTERVAL 1 MONTH) |
+--------------------------------------------------+
| 2009-02-28 23:59:59                              | 
+--------------------------------------------------+

I understand why it works that way, but it certainly isn't ideal, nor
is it precise if you aren't expecting that.  Neither way is perfect.  We
chose to have all relative date operations follow the same rules. 
Having Interval and Modify use different relative date rules would be
very confusing.

------------------------------------------------------------------------

[2009-08-07 00:22:37] brad at omnis dot com

Why have dateInterval at all?  If you don't want to have "2
different implementations".  dateTime::modify() existed prior to PHP
5.3.0 and did the job of strtotime().  All dateInterval does at this
point is to confuse anyone who thinks it may add time in a
non-GNU-strtotime way and do calendar math.

If I wanted strtotime capability with dateTime objects I could just use
dateTime::modify() could I not?

What is the issue with having dateInterval work in a calendar math way
and having dateTime::modify() work the old unix way?  Both sides would
be happy.

(Also, http://bugs.php.net/bug.php?id=43999 is about strtotime
specifically.  There is nothing obvious that dateInterval has anything
to do with strtotime)

------------------------------------------------------------------------

[2009-08-06 23:40:54] ras...@php.net

Well, it uses the same strtotime code.  We are not going to have 2
different implementations here.  I have no difficulty understanding that
some people might expect database-like behaviour,  But at the same time,
there are also people who expect UNIX-like behaviour.  You seem to be
discounting those, and in the end we had to choose one or the other.

And the reason it was marked bogus was because it had been filed
before.  A quick search finds the previous bugs easily.

------------------------------------------------------------------------

[2009-08-06 22:53:57] brad at omnis dot com

Notice I'm not complaining about the dateTime::modify() function, which
explicitly states it uses strtotime() format.  I'm taking about a
function that explicitly states "Adds an amount of days, months, years,
hours, minutes and seconds to a DateTime object",

I'm not making any claim that you "made this stuff up".  I would argue
that the GNU guys got it wrong (see the example of how databases handle
it for an alternate point of view), but that's not the issue.  I'm
talking about PHP here, not GNU.

What is so difficult to understand that people using these sets of
functions might expect that it works in the same manner that databases
do.

I've been using PHP for 10+ years, I'm not trying to make you mad, I'm
trying to help make PHP better by filing bug reports, and what do I get
in response to a legitimate issue?  I get it marked as BOGUS.

A compromise of making the dateInterval constructor have a "[, bool
$calendarMath]" (or a bitmask) option would be welcome, but leaving it
as is, I believe will lead to confusion and headache for those wishing
to use these functions for anything that requires precision math
calculations.

------------------------------------------------------------------------

[2009-08-06 22:32:25] ras...@php.net

We didn't make this stuff up.  We followed the GNU strtotime
implementation.  And it isn't as cut and dry as you make it sound that
shrinking the interval is the right approach when you are at the end of
the month and the next month is shorter.  

Given the complexity of this stuff, we figured following traditional
UNIX practice would make the most sense.  You can read about it here:

http://www.gnu.org/software/tar/manual/html_chapter/Date-input-formats.html#SEC114

And if you read this section:

http://www.gnu.org/software/tar/manual/html_chapter/Date-input-formats.html#SEC120

They even specifically mention this case:

"The fuzz in units can cause problems with relative items. For example,
‘2003-07-31 -1 month’ might evaluate to 2003-07-01, because 2003-06-31
is an invalid date. To determine the previous month more reliably, you
can ask for the month before the 15th of the current month. "

So, can we drop this "The PHP Devs don't want to write correct code"
ranting please, and recognize that you simply don't agree with our
choice.  It has nothing to do with correctness.  Your shell's date
command behaves exactly the same way, as does any other UNIX command
that uses relative dates.



------------------------------------------------------------------------

The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
    http://bugs.php.net/48824

-- 
Edit this bug report at http://bugs.php.net/?id=48824&edit=1

Reply via email to