1

I have the following example of me subtracting the DateInterval from DateTimeImmutable

    $dateA = new DateTimeImmutable('2016-06-30');
    $dateB = new DateTimeImmutable('2016-05-31');
    $dateInterval = new DateInterval('P3M');
    // print 2016-03-30 as expected
    echo $dateA->sub($dateInterval)->format('Y-m-d'); 
    // print 2016-03-02 which i would expect 2016-02-29
    echo $dateB->sub($dateInterval)->format('Y-m-d');

When I set the period to 'P8M' it works as expected. How it comes, it dosent works for february?

Jan Tajovsky
  • 1,162
  • 2
  • 13
  • 34
  • It because 30th of february come to be 2016-03-02. But if you set date to 1-28th it will work as you expect – splash58 Jun 01 '16 at 15:52
  • Why is this always "unexpected"? – Mark Baker Jun 01 '16 at 15:54
  • @MarkBaker probably, while set date to the last day of a month, somebody want to get in this way the last day of another month – splash58 Jun 01 '16 at 15:56
  • @splash58 I understand what they want, I just don't understand why documented behaviour is "unexpected" – Mark Baker Jun 01 '16 at 15:57
  • @MarkBaker Watching questions on the site, I think nobody read the docs. Or it is written unclear :) – splash58 Jun 01 '16 at 16:04
  • 2
    @splash58 this year (2016) is a leap year with 29 days in February. The '30th' of Feb would be 2016-03-01 – Ray Jun 01 '16 at 16:06
  • @Ray I'm wrong. PO substact from dateB ('2016-05-31') , not dateA – splash58 Jun 01 '16 at 16:09
  • Can anyone point out where in 'the docs' a good explanation of how Month intervals are determined? – Ray Jun 01 '16 at 16:11
  • @Ray - added as an answer – Mark Baker Jun 01 '16 at 16:23
  • @MarkBaker When the behaviour is not intuitive and needs to be documented I would call it 'unexpected' as I did not expect it. Quite simple isn't it? – Jan Tajovsky Jun 01 '16 at 16:33
  • 1
    Actually, I'd say that it's perfectly logical behaviour for a computer.... computers aren't intuitive, they don't have intelligence, they simply follow a set of predefined rules.... topics like dates need extensive doocumentation because of the lack of human intelligence (e.g. variations in date format between US and UK/European formats, where explanation is required); not because it's abstruse computer logic, but to ensure that human beings in different parts of the world understand the differences – Mark Baker Jun 01 '16 at 16:39

2 Answers2

2

Ok, it's really simple (kind of). Each 'month' interval evaluates to the prior (or X number of prior) month's equivalent day. If there are more days in the current month, than the month being landed on, the excess overflows to the following month.

So if you have a date which is May 31, 2016 and want to subtract 3 month intervals, it will:

  • Go back 3 months (in the list of months, don't think days yet), resulting in 'February'
  • Then look for February 31st. This doesn't exist so bleed over to following month 2 days (2016 Febuary has 29 days, so 2 extra days)
  • Viola! March 2nd.

Go forward, lets say you're in May 31, 2016 and want to add one month

  • Go forward one month to June.
  • Look for June 31st, nope, 1 extra day, bleed over to July.
  • As expected, July 1st is the answer.

The lesson in this: Adding and Subtracting Month intervals sucks, is confusing, and can lead to non-intuitive results unless you've got your month calculation rosetta stone with you.

Ray
  • 40,256
  • 21
  • 101
  • 138
0

Explanation from the PHP Docs

Note: Relative month values are calculated based on the length of months that they pass through. An example would be "+2 month 2011-11-30", which would produce "2012-01-30". This is due to November being 30 days in length, and December being 31 days in length, producing a total of 61 days.

Mark Baker
  • 209,507
  • 32
  • 346
  • 385
  • Thanks I had no idea there was a Relative format page. I still find the month explanation a bit confusing, can you look at my answer and see if its more intuitive (or incorrect)? – Ray Jun 01 '16 at 16:32