Skip to content

Fix whereBetween to accept DatePeriod and handle missing end dates (#58092)#58687

Merged
taylorotwell merged 3 commits intolaravel:12.xfrom
HeathNaylor:bugfix/where-between-date-period
Feb 9, 2026
Merged

Fix whereBetween to accept DatePeriod and handle missing end dates (#58092)#58687
taylorotwell merged 3 commits intolaravel:12.xfrom
HeathNaylor:bugfix/where-between-date-period

Conversation

@HeathNaylor
Copy link
Contributor

Fixes #58092

whereBetween and havingBetween used CarbonPeriod instead of DatePeriod.

This PR changes instanceof CarbonPeriod to instanceof \DatePeriod which is backward compatible and calculates the end date from when getEndDate() is null

Respecting EXCLUDE_START_DATE / INCLUDE_END_DATE flags is a behavioral change and needs to be in a separate issue to target master.

* Resolve the start and end dates from a DatePeriod.
*
* @param \DatePeriod $period
* @return array
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could define a tuple here:

Suggested change
* @return array
* @return array{\DateTimeInterface, \DateTimeInterface}

if ($end === null) {
$end = clone $start;

for ($i = 0; $i < $period->getRecurrences(); $i++) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might slightly improve performance if you avoid getting the recurrences on every iteration

Suggested change
for ($i = 0; $i < $period->getRecurrences(); $i++) {
$recurrences = $period->getRecurrences();
for ($i = 0; $i < $recurrences; $i++) {

or

Suggested change
for ($i = 0; $i < $period->getRecurrences(); $i++) {
for ($i = 0, $recurrences = $period->getRecurrences(); $i < $recurrences(); $i++) {

@taylorotwell taylorotwell merged commit e8f4b59 into laravel:12.x Feb 9, 2026
70 checks passed
mosabbirrakib added a commit to mosabbirrakib/framework that referenced this pull request Feb 15, 2026
…whereBetween/havingBetween

This PR adds comprehensive integration tests for the DatePeriod support that was added in PR laravel#58687.

## Problem

While PR laravel#58687 added DatePeriod support to whereBetween() and havingBetween() methods with unit tests, it lacks comprehensive integration tests that verify the feature works correctly with real database queries.

## Solution

This PR adds comprehensive integration tests in QueryBuilderDatePeriodTest.php that test all DatePeriod scenarios with actual database queries:

- whereBetween with DatePeriod
- whereBetween with CarbonPeriod
- whereBetween with recurrences (no end date)
- whereBetween with EXCLUDE_START_DATE flag
- whereBetween with INCLUDE_END_DATE flag
- whereBetween with both flags combined
- whereNotBetween with DatePeriod
- whereNotBetween with EXCLUDE_START_DATE flag
- havingBetween with DatePeriod (grouped queries)
- havingNotBetween with DatePeriod
- orWhereBetween with DatePeriod
- orWhereNotBetween with DatePeriod

## Benefits to End Users

These integration tests ensure that:
1. DatePeriod works correctly with real database queries
2. All edge cases are covered (recurrences, inclusion/exclusion flags)
3. The feature works across different database drivers
4. Future changes won't break DatePeriod support

## Breaking Changes

None. This only adds tests for existing functionality.

Relates to laravel#58092
mosabbirrakib added a commit to mosabbirrakib/framework that referenced this pull request Feb 15, 2026
…inclusion/exclusion flags

This PR enhances the DatePeriod support in whereBetween() and havingBetween() methods to properly handle DatePeriod inclusion/exclusion flags and NOT BETWEEN logic.

## Problem

While PR laravel#58687 added basic DatePeriod support to whereBetween() and havingBetween(), it has several limitations:

1. **Ignores inclusion/exclusion flags**: DatePeriod supports EXCLUDE_START_DATE and INCLUDE_END_DATE flags, but the current implementation doesn't respect them
2. **Incorrect NOT BETWEEN logic**: The current implementation doesn't handle whereNotBetween() and havingNotBetween() correctly with DatePeriod
3. **Limited test coverage**: Only has basic unit tests, lacks comprehensive integration tests

## Solution

This PR enhances the DatePeriod support by:

1. **Respecting inclusion/exclusion flags**: Uses correct operators (>, >=, <, <=) based on DatePeriod flags
2. **Fixing NOT BETWEEN logic**: Properly implements NOT BETWEEN using OR logic (value < start OR value > end)
3. **Adding comprehensive integration tests**: 12 integration test methods covering all scenarios

## Implementation Details

### whereBetweenDatePeriod() Method

- Extracts start and end dates from DatePeriod
- Calculates end date from recurrences if needed
- Determines operators based on include_start_date and include_end_date flags
- For NOT BETWEEN: Uses OR logic (value < start OR value > end)
- For BETWEEN: Uses AND logic with appropriate operators

### havingBetweenDatePeriod() Method

- Same logic as whereBetweenDatePeriod() but for HAVING clauses
- Uses havingRaw() for NOT BETWEEN to properly handle OR logic

## Benefits to End Users

### Before (ignores flags):

```php
// Ignores EXCLUDE_START_DATE flag
$period = new DatePeriod(
    new DateTime('2024-01-01'),
    new DateInterval('P1D'),
    new DateTime('2024-01-31'),
    DatePeriod::EXCLUDE_START_DATE
);
User::whereBetween('created_at', $period)->get(); // Still includes Jan 1st ❌

// Ignores INCLUDE_END_DATE flag
$period = new DatePeriod(
    new DateTime('2024-01-01'),
    new DateInterval('P1D'),
    new DateTime('2024-01-31'),
    DatePeriod::INCLUDE_END_DATE
);
User::whereBetween('created_at', $period)->get(); // Doesn't include Jan 31st ❌
```

### After (respects flags):

```php
// Respects EXCLUDE_START_DATE flag
$period = new DatePeriod(
    new DateTime('2024-01-01'),
    new DateInterval('P1D'),
    new DateTime('2024-01-31'),
    DatePeriod::EXCLUDE_START_DATE
);
User::whereBetween('created_at', $period)->get(); // Excludes Jan 1st ✅

// Respects INCLUDE_END_DATE flag
$period = new DatePeriod(
    new DateTime('2024-01-01'),
    new DateInterval('P1D'),
    new DateTime('2024-01-31'),
    DatePeriod::INCLUDE_END_DATE
);
User::whereBetween('created_at', $period)->get(); // Includes Jan 31st ✅
```

## Tests Added

### Integration Tests (12 methods):

✅ whereBetween with DatePeriod
✅ whereBetween with CarbonPeriod
✅ whereBetween with recurrences (no end date)
✅ whereBetween with EXCLUDE_START_DATE flag
✅ whereBetween with INCLUDE_END_DATE flag
✅ whereBetween with both flags combined
✅ whereNotBetween with DatePeriod
✅ whereNotBetween with EXCLUDE_START_DATE flag
✅ havingBetween with DatePeriod (grouped queries)
✅ havingNotBetween with DatePeriod
✅ orWhereBetween with DatePeriod
✅ orWhereNotBetween with DatePeriod

All tests use real database queries with actual data to ensure the feature works correctly across all supported database drivers.

## Breaking Changes

None. This is purely additive and enhances existing functionality.

## Code Changes

- **Modified**: src/Illuminate/Database/Query/Builder.php (+98 -5 lines)
  - Added whereBetweenDatePeriod() protected method
  - Added havingBetweenDatePeriod() protected method
  - Enhanced whereBetween() to delegate to whereBetweenDatePeriod()
  - Enhanced havingBetween() to delegate to havingBetweenDatePeriod()

- **New file**: tests/Integration/Database/QueryBuilderDatePeriodTest.php (268 lines)
  - 12 comprehensive integration test methods
  - Tests all DatePeriod scenarios with real database queries

Fixes laravel#58092
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Eloquent whereBetween with DatePeriod

3 participants

Comments