php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #80696 Subtracting an interval of 1 month 1 day subtracts one more day
Submitted: 2021-02-01 23:33 UTC Modified: 2021-02-02 02:22 UTC
Votes:2
Avg. Score:4.0 ± 1.0
Reproduced:2 of 2 (100.0%)
Same Version:2 (100.0%)
Same OS:1 (50.0%)
From: jurchiks101 at gmail dot com Assigned:
Status: Not a bug Package: Date/time related
PHP Version: 7.4.14 OS: Windows 10
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: jurchiks101 at gmail dot com
New email:
PHP Version: OS:

 

 [2021-02-01 23:33 UTC] jurchiks101 at gmail dot com
Description:
------------
When subtracting an interval that contains months and days, the number of days subtracted is sometimes increased by an inconsistent amount.

Here's the 3v4l: https://3v4l.org/uIWq4

Test script:
---------------
$firstDayOfYear = new DateTimeImmutable('2021-01-01 00:00:00.000000');


for ($i = 1; $i <= 12; $i++) {
    $intervalOneEach = new DateInterval('P' . $i . 'M1D');
    echo $firstDayOfYear
        ->sub($intervalOneEach)
        ->diff($firstDayOfYear)
        ->format('%y years %m months %d days %h hours %i minutes %s seconds'), PHP_EOL;
}


Expected result:
----------------
0 years 1 months 1 days 0 hours 0 minutes 0 seconds
0 years 2 months 1 days 0 hours 0 minutes 0 seconds
0 years 3 months 1 days 0 hours 0 minutes 0 seconds
0 years 4 months 1 days 0 hours 0 minutes 0 seconds
0 years 5 months 1 days 0 hours 0 minutes 0 seconds
0 years 6 months 1 days 0 hours 0 minutes 0 seconds
0 years 7 months 1 days 0 hours 0 minutes 0 seconds
0 years 8 months 1 days 0 hours 0 minutes 0 seconds
0 years 9 months 1 days 0 hours 0 minutes 0 seconds
0 years 10 months 1 days 0 hours 0 minutes 0 seconds
0 years 11 months 1 days 0 hours 0 minutes 0 seconds
1 years 0 months 1 days 0 hours 0 minutes 0 seconds

Actual result:
--------------
0 years 1 months 2 days 0 hours 0 minutes 0 seconds
0 years 2 months 1 days 0 hours 0 minutes 0 seconds
0 years 3 months 2 days 0 hours 0 minutes 0 seconds
0 years 4 months 1 days 0 hours 0 minutes 0 seconds
0 years 5 months 1 days 0 hours 0 minutes 0 seconds
0 years 6 months 2 days 0 hours 0 minutes 0 seconds
0 years 7 months 1 days 0 hours 0 minutes 0 seconds
0 years 8 months 2 days 0 hours 0 minutes 0 seconds
0 years 9 months 1 days 0 hours 0 minutes 0 seconds
0 years 10 months 3 days 0 hours 0 minutes 0 seconds
0 years 11 months 1 days 0 hours 0 minutes 0 seconds
1 years 0 months 1 days 0 hours 0 minutes 0 seconds

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-02-02 00:53 UTC] requinix@php.net
-Status: Open +Status: Not a bug
 [2021-02-02 00:53 UTC] requinix@php.net
You calculate the diff by counting days before months. PHP calculates the diff by counting months before days.

Dates are hard.
 [2021-02-02 00:58 UTC] jurchiks101 at gmail dot com
Well that makes no sense. Great!
 [2021-02-02 01:05 UTC] requinix@php.net
What part, my brief explanation or PHP's behavior? I'll assume the former.
That's good because it gives me a chance to mention that I got it backwards.

2021-01-01 minus P1M1D is 2020-11-30. Agreed on that?

2020-11-30 plus P1M = 2020-12-30
2020-12-30 plus P1D = 2021-12-31

Compare with

2020-11-30 plus P1D = 2020-12-01
2020-12-01 plus P1M = 2021-01-01

Same starting date, same ending date, different intervals depending how you count it.
 [2021-02-02 01:24 UTC] jurchiks101 at gmail dot com
Is it that PHP subtracts and adds using the same order?
It would seem to me that the solution is to flip the order depending on the operation:

2021-01-01 - P1M = 2020-12-01
2020-12-01 - P1D = 2020-11-31
reverse:
2020-11-31 + P1D = 2020-12-01
2020-12-01 + P1M = 2021-01-01
 [2021-02-02 02:22 UTC] requinix@php.net
> It would seem to me that the solution is to flip the order depending on the operation:
There is no solution here. Not simply because "this isn't a bug" but because changing how the diff is calculated to suit your expectations will cause issues for everyone else who thinks the diff should be the way it is now.

Like I said: dates are hard.

I don't know what your use case here is but depending on these diffs to work a certain way might not be the right answer.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri May 03 19:01:32 2024 UTC