[php-src] Issue #8275: Function strtotime("-x month", ...) returns different month if the date part is 01-28 or >=29. Additionally different
behaviour for leap and non-leap years

From: Date: Wed, 30 Mar 2022 07:27:28 +0000
Subject: [php-src] Issue #8275: Function strtotime("-x month", ...) returns different month if the date part is 01-28 or >=29. Additionally different
behaviour for leap and non-leap years
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-240565@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/8275 Author: sathishpaniker ### Description Date('Y-m-01', strtotime("-1 month", strtotime(Date("2022-03-28")))) is returning '2022-02-01', but Date('Y-m-01', strtotime("-1 month", strtotime(Date("2022-03-29")))) is returning '2022-03-01'. This behaviour fails on different months and also based on year is leap year or not. Hence, added a code which could cover all scenarios The following code: ```php <?php function date_function_check($year, $month, $isleapyear) { echo "\n\n========= "; echo "Testing for YEAR = $year , which is" . (!$isleapyear ? " NOT" : "") . " a Leap Year"; echo " ========\n"; // Loop through for ($month = 1; $month <= 12; $month++) { if (($month == 2) && (!$isleapyear)) { continue; } // skipiing as Feb has 28 todays except for leap year if ($month < 10) {$mn = "0" . $month; } else {$mn = "" . $month; } // Create a date and time variable for day = 28 $day = '28'; $dta = Date($year . "-" . $mn . "-" . $day); $tma = strtotime($dta); // Create a date and time variable for day = 28 $day = '29'; $dtb = Date($year . "-" . $mn . "-" . $day); $tmb = strtotime($dtb); // Starting the test with the created reference dates echo "\n\n $month. Performing TEST with dates as $dta and $dtb scenario"; // Get all last 12 months using Date("-x month", ...) date function for ($i = 1; $i <= 12; $i++) { $j = $i * -1; $newdt1 = Date('Y-m-01', strtotime($j . " month", $tma)); $newdt2 = Date('Y-m-01', strtotime($j . " month", $tmb)); if ($newdt1 !== $newdt2) { echo "\n Testing condition : \"" . $j . " month\" as parameter"; echo "\n - If PHP statement : Date('Y-m-01', strtotime(\"" . $j . " month\", strtotime(Date(\"" . $dta . "\"))))\n"; echo " Value returned is " . $newdt1 . "\n"; echo " - If PHP statement : Date('Y-m-01', strtotime(\"" . $j . " month\", strtotime(Date(\"" . $dtb . "\"))))\n"; echo " Incorrect Date Value returned is " . $newdt2 . " (Expected Date: " . $newdt1 . ")\n"; } } } echo "\n"; } // Main section date_function_check('2022', 1, false); // Not a leap year date_function_check('2024', 1, true); // Is a leap year ``` Resulted in this output: ``` ========= Testing for YEAR = 2022 , which is NOT a Leap Year ======== 1. Performing TEST with dates as 2022-01-28 and 2022-01-29 scenario Testing condition : "-11 month" as parameter - If PHP statement : Date('Y-m-01', strtotime("-11 month", strtotime(Date("2022-01-28")))) Value returned is 2021-02-01 - If PHP statement : Date('Y-m-01', strtotime("-11 month", strtotime(Date("2022-01-29")))) Incorrect Date Value returned is 2021-03-01 (Expected Date: 2021-02-01) 3. Performing TEST with dates as 2022-03-28 and 2022-03-29 scenario Testing condition : "-1 month" as parameter - If PHP statement : Date('Y-m-01', strtotime("-1 month", strtotime(Date("2022-03-28")))) Value returned is 2022-02-01 - If PHP statement : Date('Y-m-01', strtotime("-1 month", strtotime(Date("2022-03-29")))) Incorrect Date Value returned is 2022-03-01 (Expected Date: 2022-02-01) 4. Performing TEST with dates as 2022-04-28 and 2022-04-29 scenario Testing condition : "-2 month" as parameter - If PHP statement : Date('Y-m-01', strtotime("-2 month", strtotime(Date("2022-04-28")))) Value returned is 2022-02-01 - If PHP statement : Date('Y-m-01', strtotime("-2 month", strtotime(Date("2022-04-29")))) Incorrect Date Value returned is 2022-03-01 (Expected Date: 2022-02-01) 5. Performing TEST with dates as 2022-05-28 and 2022-05-29 scenario Testing condition : "-3 month" as parameter - If PHP statement : Date('Y-m-01', strtotime("-3 month", strtotime(Date("2022-05-28")))) Value returned is 2022-02-01 - If PHP statement : Date('Y-m-01', strtotime("-3 month", strtotime(Date("2022-05-29")))) Incorrect Date Value returned is 2022-03-01 (Expected Date: 2022-02-01) 6. Performing TEST with dates as 2022-06-28 and 2022-06-29 scenario Testing condition : "-4 month" as parameter - If PHP statement : Date('Y-m-01', strtotime("-4 month", strtotime(Date("2022-06-28")))) Value returned is 2022-02-01 - If PHP statement : Date('Y-m-01', strtotime("-4 month", strtotime(Date("2022-06-29")))) Incorrect Date Value returned is 2022-03-01 (Expected Date: 2022-02-01) 7. Performing TEST with dates as 2022-07-28 and 2022-07-29 scenario Testing condition : "-5 month" as parameter - If PHP statement : Date('Y-m-01', strtotime("-5 month", strtotime(Date("2022-07-28")))) Value returned is 2022-02-01 - If PHP statement : Date('Y-m-01', strtotime("-5 month", strtotime(Date("2022-07-29")))) Incorrect Date Value returned is 2022-03-01 (Expected Date: 2022-02-01) 8. Performing TEST with dates as 2022-08-28 and 2022-08-29 scenario Testing condition : "-6 month" as parameter - If PHP statement : Date('Y-m-01', strtotime("-6 month", strtotime(Date("2022-08-28")))) Value returned is 2022-02-01 - If PHP statement : Date('Y-m-01', strtotime("-6 month", strtotime(Date("2022-08-29")))) Incorrect Date Value returned is 2022-03-01 (Expected Date: 2022-02-01) 9. Performing TEST with dates as 2022-09-28 and 2022-09-29 scenario Testing condition : "-7 month" as parameter - If PHP statement : Date('Y-m-01', strtotime("-7 month", strtotime(Date("2022-09-28")))) Value returned is 2022-02-01 - If PHP statement : Date('Y-m-01', strtotime("-7 month", strtotime(Date("2022-09-29")))) Incorrect Date Value returned is 2022-03-01 (Expected Date: 2022-02-01) 10. Performing TEST with dates as 2022-10-28 and 2022-10-29 scenario Testing condition : "-8 month" as parameter - If PHP statement : Date('Y-m-01', strtotime("-8 month", strtotime(Date("2022-10-28")))) Value returned is 2022-02-01 - If PHP statement : Date('Y-m-01', strtotime("-8 month", strtotime(Date("2022-10-29")))) Incorrect Date Value returned is 2022-03-01 (Expected Date: 2022-02-01) 11. Performing TEST with dates as 2022-11-28 and 2022-11-29 scenario Testing condition : "-9 month" as parameter - If PHP statement : Date('Y-m-01', strtotime("-9 month", strtotime(Date("2022-11-28")))) Value returned is 2022-02-01 - If PHP statement : Date('Y-m-01', strtotime("-9 month", strtotime(Date("2022-11-29")))) Incorrect Date Value returned is 2022-03-01 (Expected Date: 2022-02-01) 12. Performing TEST with dates as 2022-12-28 and 2022-12-29 scenario Testing condition : "-10 month" as parameter - If PHP statement : Date('Y-m-01', strtotime("-10 month", strtotime(Date("2022-12-28")))) Value returned is 2022-02-01 - If PHP statement : Date('Y-m-01', strtotime("-10 month", strtotime(Date("2022-12-29")))) Incorrect Date Value returned is 2022-03-01 (Expected Date: 2022-02-01) ========= Testing for YEAR = 2024 , which is a Leap Year ======== 1. Performing TEST with dates as 2024-01-28 and 2024-01-29 scenario Testing condition : "-11 month" as parameter - If PHP statement : Date('Y-m-01', strtotime("-11 month", strtotime(Date("2024-01-28")))) Value returned is 2023-02-01 - If PHP statement : Date('Y-m-01', strtotime("-11 month", strtotime(Date("2024-01-29")))) Incorrect Date Value returned is 2023-03-01 (Expected Date: 2023-02-01) 2. Performing TEST with dates as 2024-02-28 and 2024-02-29 scenario Testing condition : "-12 month" as parameter - If PHP statement : Date('Y-m-01', strtotime("-12 month", strtotime(Date("2024-02-28")))) Value returned is 2023-02-01 - If PHP statement : Date('Y-m-01', strtotime("-12 month", strtotime(Date("2024-02-29")))) Incorrect Date Value returned is 2023-03-01 (Expected Date: 2023-02-01) 3. Performing TEST with dates as 2024-03-28 and 2024-03-29 scenario 4. Performing TEST with dates as 2024-04-28 and 2024-04-29 scenario 5. Performing TEST with dates as 2024-05-28 and 2024-05-29 scenario 6. Performing TEST with dates as 2024-06-28 and 2024-06-29 scenario 7. Performing TEST with dates as 2024-07-28 and 2024-07-29 scenario 8. Performing TEST with dates as 2024-08-28 and 2024-08-29 scenario 9. Performing TEST with dates as 2024-09-28 and 2024-09-29 scenario 10. Performing TEST with dates as 2024-10-28 and 2024-10-29 scenario 11. Performing TEST with dates as 2024-11-28 and 2024-11-29 scenario 12. Performing TEST with dates as 2024-12-28 and 2024-12-29 scenario ``` But I expected this output instead: ``` For e.g., For year and month (2022 and Mar) Date('Y-m-01', strtotime("-1 month", strtotime(Date("2022-03-28")))) should return '2022-02-01' Date('Y-m-01', strtotime("-1 month", strtotime(Date("2022-03-29")))) should return '2022-02-01' Additionally, the behaviour needs to work for both leap and non-leap years ``` ### PHP Version PHP 8.1.3 ### Operating System _No response_

« previous php.bugs (#240565) next »