Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

renzz17's avatar

NOW whereBetween two database dates

Hi,

So I was wondering if it's possible to check if the current time is between 2 date fields in the database?

I was thinking of something like this, but this isn't working:

Screen::find($id)->items()
                  ->where('show_from', '<=', Carbon::now())
                  ->where('show_till', '>=', Carbon::now())->get();
0 likes
14 replies
richard's avatar

Are the dates in show_from and show_till column Carbon instances?

You need to declare them inside the 'items' Model.

protected $dates = ['show_from', 'show_till'];
1 like
renzz17's avatar

Thanks for the response!

So I added the dates to my Item Model, but I still don't get the items that are currently (current time) between the show_from and show_till time.

Maybe it's because they are in a pivot table?

This is what I have in my Screen Model

public function items()
    {
        return $this->belongsToMany(Item::class)->withPivot('id', 'screen_id', 'content', 'item_order', 'approved', 'show_from', 'show_till')->withTimestamps()->orderBy('item_order', 'asc');
    }
willvincent's avatar

You'd need a whereBetween clause to specify that Carbon::now() is between show_from and show_till... and really, if you're loading that much extra data into your pivot table, you're probably better off using a model to represent the pivot rather than withPivot.

Or maybe I'm misunderstanding. But it sounds like you have these dates, the order, etc on the pivot table, rather than on the Item table where they more likely belong.

1 like
renzz17's avatar

@willvincent but the whereBetween clause only lets me specify 2 parameters, a database field and a array of 2 dates of a range. Is it possible to do the opposite? Have 2 fields from the database as range and 1 field as Carbon::now()?

And thanks for the advice, they do belong in a pivot as the Item has data that can be used multiple times. I didn't knew I could create a model for a pivot.

sabuncuserhat's avatar

Can you check like this ?

$show_from = Screen::find($id)->items()
                  ->where('show_from', '<=', Carbon::now())->get();

$show_till = Screen::find($id)->items()
                   ->where('show_till', '>=', Carbon::now())->get();


$screen = $show_from->merge($show_till );

return $screen;

OR

Screen::find($id)->items()
                  ->where('show_from', '<=', Carbon::now())
                  ->orWhere('show_till', '>=', Carbon::now())->get();
1 like
renzz17's avatar

@sabuncuserhat I don't think that will work as both checks need to be in 1 query, else it will still show the outdated items.

So it needs to be within show_from AND show_till. If I do a OR statement it will show the outdated items too.

willvincent's avatar
Level 54

Use a closure?

->where(function ($q) {
  $q->where('show_from', '<=', Carbon::now());
  $q->where('show_till', '>=', Carbon::now());
})

That will ensure that these two conditions must be true -- independent of any other where clauses.

In other words, when the query string is written, these will be within a set of parenthesis:

SELECT * FROM Foo WHERE (show_from <= whatever AND show_till >= whatever)

4 likes
jlrdw's avatar

Or just use keyboard and type something like

SELECT * FROM Foo WHERE show_from Between begindate AND enddate

And you DO NOT need carbon to do things like this.

willvincent's avatar

@jlrdw That's not what is being asked.

Specifically @renzz17 is looking for records where the current date/time is between show_from and show_till fields.

And, specifically wanting to do so with eloquent -- suggesting otherwise is really counter productive.

eyzae's avatar

@willvincent your solution worked perfectly for me but I'm having an issue with UTC conversion and I was wondering if you knew a solution (yes, I know this conversation is old and you might not be around to solve it).

I have a table that has a field labelled 'start_at' and a field labelled 'end_at' and these store times when someone is available to work, and it stores these values in UTC (so if I can work 2pm - 10pm then it is stored in the DB as 18:00:00 and 02:00:00 respectively). So right about now you should see where my dilemma is with your above code. If it is currently 5pm local time, converted to UTC that would be 21:00:00, and that would satisfy the first 'where' clause but it would fail the second 'where' clause (as 02:00:00 is not > 21:00:00).

So my question is, in the 'where' clause is there a way to convert the 'show_from' and 'show_till' fields to my current timezone before doing the comparison?

Thank you

willvincent's avatar

@eyzae Yea, that can present a challenge when you're comparing a date agnostic time of day with a timestamp.

But, I think you can manage it with something along these lines:

->where(function ($q) {
  $tz_offset = "-6:00"; // Whatever the user's timezone offset is
  $q->whereRaw("CONVERT_TZ('available_from', '+0:00', ?) <= ?', [$tz_offset, Carbon::now()]);
  $q->whereRaw("CONVERT_TZ('available_to', '+0:00', ?) <= ?', [$tz_offset, Carbon::now()]);
})

This is untested, but should get you in the ballpark. Syntax would be entirely different for postgres or sqlite, so.. frankly you might be best off NOT using UTC for these fields. Though you could still run into issues if you need to support a 3rd shift scenario where someone works say 11p - 7a or whatever. Not sure off the top of my head the best solution in that case. This isn't really a problem space I find myself having had to deal with any time in recent memory and not really feeling like spending a ton of effort on thinking through all of the logic - though I suspect if you had to handle something like that were available hours span across days, you might add a flag to that record so that you could conditionally apply different query logic. 🤷‍♂️

1 like
eyzae's avatar

@willvincent Thank you for all your help. I couldn't get it to work exactly how I wanted so I added in a couple of different '->where' clauses to my scope to check for 'available_from' and now(), and 'available_to' and now() (to check for things like if they are working a night shift that goes in to the next day, etc.) like you said.

Thank you again for your help, especially on a 4 year old question.

1 like
willvincent's avatar

@eyzae Yeah, that's an edge case where I don't think you can really do it with a 'between' query. Glad to hear you got it sorted. 👍

Please or to participate in this conversation.