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

robjbrain's avatar

MySQL/Eloquent: Grouping by date in users timezone

This may be able to be answered simply as a MySQL rather than a Laravel specific answer, although of course I am using Laravel and Eloquent so if there's a method within Laravel\Eloquent to do this that would be awesome.

My database is in UTC. I want to get a count of how many comments where posted each day so show on a graph, so I do something like this:

select DATE(created_at) as date, count(*) as count from `social_forum_comments` group by `date`

Very simple, this works perfectly for me.

However, if someone is in Australia, the counts won't accurately reflect a day in THEIR timezone, but a day in UTC.

I'll try and re-iterate:

What I want is the count between these dates: "2017-11-05 00:00:00" and "2017-11-05 23:59:59" in the users local timezone.

With the above query if an Australian is on the site, it will be showing a count from "2017-11-05 10:00:00" and "2017-11-06 09:59:59" (where the users timezone is UTC +10)

If it was just one query that may be easier to do, but since I want it grouped by day and showing a whole month (for a graph) i'm not sure how that would be possible?

Is there a way to do this via Eloquent? perhaps setting the timezone on connection or something like that?

0 likes
6 replies
bobbybouwmann's avatar

I believe you can convert the timezones while selecting the data to another timezone, that might be what your looking for: https://stackoverflow.com/questions/15017799/how-to-convert-utc-date-to-local-time-zone-in-mysql-select-query

However it's still a hard proces. Just thinking out of the box, but wouldn't it be better to give it a where in statement and select the count per day? This way you have control over what timezone you pick.

Also wondering why you want to display it differently? I mean when I reply today on 7:34. It might be a different time in Australia, but they still see the comment right away right? For them I still replied the same day! Not really sure if your making it harder than it should be. That's my 2 cents

robjbrain's avatar

Well if you're in Australia and you say I want to know to how many XXX happened on November 7th, you care about your November 7th not British, French or American November 7th right, they mean nothing to you.

I'm not sure if i've misunderstood you or you've misunderstood me on that last paragraph :)

Thanks for the link, that works perfectly actually, albeit not that attractive to look at.

select DATE(CONVERT_TZ(created_at,'+00:00','+10:00') as date, count(*) as count from `social_forum_comments` group by `date`

In Laravel it seems like I can do this:

$results = DB::table('social_forum_comments')
    ->select(DB::raw("DATE(CONVERT_TZ(created_at,'+00:00'," . $user->getTimezoneOffset() . ") as date, count(*) as count"))
    ->groupBy('date')
    ->get();

$stats = collect($results)->pluck('count', 'date');

// And in the user class
// Timezone is a user defined column on the user table
// $timezone = "Australia/Brisbane"
class User {
    public function getTimezoneOffset() {
        return Carbon::now()->setTimezone($this->timezone)->format('P');
    }
}

I'm not sure if that's actually the best way to do it, it's certainly not the most 'eloquent' but it works. I couldn't figure out a better function for getting the offset and there's probably no need to use Carbon instead of just DateTime but i'm just used to using Carbon by default now.

1 like
robjbrain's avatar

Actually i've just discovered if you load the timezones into mysql then you don't need to work out the offest and can just do:

// $user->timezone = 'Australia/Brisbane'
$results = DB::table('social_forum_comments')
    ->select(DB::raw("DATE(CONVERT_TZ(created_at,'UTC','" . $user->timezone . "') as date, count(*) as count"))
    ->groupBy('date')
    ->get();

$stats = collect($results)->pluck('count', 'date');
1 like
bobbybouwmann's avatar

Yes indeed! I wasn't sure if you were after this but if this works for you than great!

kfirba's avatar

@robjbrain hey!

Making the timezone calculation in your query is indeed a way to go about that, however it might get slower and slower as your database grows. Think about it, mysql isn’t magical. For reach row in your database it will convert the date to the correct timezone and then compare it. This needs a little bit more research, but I’m not sure mysql will use the index on the “created_at” column in that situation as the index is only correct for UTC timezone.

I would like to suggest an alternative way to achieve that while ensuring mysql can use an index to perform the search.

If you know the user’s timezone, you can then calculate what is the right “UTC” time that reflects their timezone. For example, if you want all data between “2017-11-05 00:00:00” and “2017-11-05 23:59:59” in the user’s timezone and you know their offset is +10hours, you can convert your UTC time t reflect that and look for any comments between “2017-11-04 14:00:00” and “2017-11-05 13:59:59”.

If you use “Carbon” this gets as easy as calling a timezone set method on the object.

After you get that done, you can use Eloquent’s “whereBetween” method to fetch those records.

Let me know if you need code samples :)!

1 like

Please or to participate in this conversation.