Commit fd658dfcb20 for woocommerce
commit fd658dfcb202226ae81c4b584a1d05e147596ad2
Author: Cvetan Cvetanov <cvetan.cvetanov@automattic.com>
Date: Thu Aug 20 13:08:00 2026 +0300
Fix last_quarter timeframe returning an invalid September 31 end date (#67787)
* Fix last_quarter timeframe returning an invalid September 31 end date
TimeInterval::get_timeframe_dates() built the Q3 end bound as "-09-31".
September has 30 days, so PHP's parser silently normalized the value to
October 1, widening the quarter by a full day.
The only consumer, TotalPaymentsVolumeProcessor, passes this string as the
"before" bound of a revenue query, so remote inbox rules using
"timeframe: last_quarter" summed an extra day of sales when evaluated
between October and December, and could match stores they should not.
Use "-09-30", and cover all four quarter ends with a test that parses each
returned value. The previous test asserted the raw string and never parsed
it, which is why it passed against an impossible date.
Refs #67786
* Add changelog entry for last_quarter end date fix
diff --git a/plugins/woocommerce/changelog/fix-last-quarter-end-date-rollover b/plugins/woocommerce/changelog/fix-last-quarter-end-date-rollover
new file mode 100644
index 00000000000..5cd5e3b221c
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-last-quarter-end-date-rollover
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Fix the last_quarter end date in TimeInterval::get_timeframe_dates(), which used an invalid September 31 and rolled over to October 1, widening the quarter by a day.
diff --git a/plugins/woocommerce/src/Admin/API/Reports/TimeInterval.php b/plugins/woocommerce/src/Admin/API/Reports/TimeInterval.php
index 9fae2a685a8..447e6d3d148 100644
--- a/plugins/woocommerce/src/Admin/API/Reports/TimeInterval.php
+++ b/plugins/woocommerce/src/Admin/API/Reports/TimeInterval.php
@@ -682,7 +682,7 @@ class TimeInterval {
case $current_month >= 10 && $current_month <= 12:
return array(
'start' => $current_year . '-07-01 00:00:00',
- 'end' => $current_year . '-09-31 23:59:59',
+ 'end' => $current_year . '-09-30 23:59:59',
);
}
}
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/api/reports-interval.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/api/reports-interval.php
index f5ece349b8d..26e7eea80f5 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/api/reports-interval.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/api/reports-interval.php
@@ -1082,7 +1082,44 @@ class WC_Admin_Tests_Reports_Interval_Stats extends WC_Unit_Test_Case {
$dates = TimeInterval::get_timeframe_dates( 'last_quarter', $datetime );
$this->assertEquals( '2022-07-01 00:00:00', $dates['start'] );
- $this->assertEquals( '2022-09-31 23:59:59', $dates['end'] );
+ $this->assertEquals( '2022-09-30 23:59:59', $dates['end'] );
+ }
+
+ /**
+ * @testdox Every "last_quarter" end date should be a real calendar date that does not roll over into the next month.
+ *
+ * @dataProvider provider_last_quarter_end_dates
+ *
+ * @param string $current_date Date the timeframe is evaluated on.
+ * @param string $expected_end Expected end of the preceding quarter.
+ */
+ public function test_timeframes_last_quarter_end_dates_are_valid_calendar_dates( $current_date, $expected_end ) {
+ $dates = TimeInterval::get_timeframe_dates( 'last_quarter', new DateTime( $current_date ) );
+
+ $this->assertEquals( $expected_end, $dates['end'] );
+
+ // String equality alone passes for invalid dates such as "-09-31", so assert the value survives parsing.
+ $parsed = new DateTime( $dates['end'] );
+
+ $this->assertEquals(
+ $expected_end,
+ $parsed->format( 'Y-m-d H:i:s' ),
+ "{$dates['end']} is not a valid calendar date and rolls over to {$parsed->format( 'Y-m-d H:i:s' )}."
+ );
+ }
+
+ /**
+ * Data provider for test_timeframes_last_quarter_end_dates_are_valid_calendar_dates.
+ *
+ * @return array
+ */
+ public function provider_last_quarter_end_dates() {
+ return array(
+ 'Q4 of the preceding year' => array( '2022-01-12', '2021-12-31 23:59:59' ),
+ 'Q1' => array( '2022-05-26', '2022-03-31 23:59:59' ),
+ 'Q2' => array( '2022-07-18', '2022-06-30 23:59:59' ),
+ 'Q3' => array( '2022-11-07', '2022-09-30 23:59:59' ),
+ );
}
/**