0

I currently store all of my dates in UTC. When a user logs in, it uses moment.js (the moment.tz.guess() function) to fill in a hidden timezone input with their timezone name e.g. America/Toronto, and then when they log in it updates their record in the database with said timezone.

I have an accessor trait I created in order to display all dates in the users timezone. See this code:

trait Timezone
{
    public function getCreatedAtAttribute($value)
    {
        return $this->timezone($value);
    }

    public function getUpdatedAtAttribute($value)
    {
        return $this->timezone($value);
    }

    public function getDeletedAtAttribute($value)
    {
        return $this->timezone($value);
    }

    // convert date to user timezone
    public function timezone($value)
    {
        $carbon = Carbon::parse($value);

        if (auth()->check()) {
            $carbon->tz(auth()->user()->timezone);
        }

        return $carbon->toDateTimeString();
    }
}

Now I am running into a small problem. I have a reporting feature in the app, and it has a dropdown where the user can select a date range such as This Week, Last Week, etc.

I will use UTC in order to query the results, and then convert it to the users timezone. The problem is that for some users, depending on the time of day, the week is showing as being from tuesday to monday, or sunday to saturday, instaed of monday to sunday.

Here is my code for that:

public static function dateStartEnd($date_range)
{
    if ($date_range == 'Today') {
        $start_date = Carbon::now()->startOfDay();
        $end_date = Carbon::now()->endOfDay();
    }
    else if ($date_range == 'Yesterday') {
        $start_date = Carbon::now()->subDay()->startOfDay();
        $end_date = Carbon::now()->subDay()->endOfDay();
    }
    else if ($date_range == 'This Week') {
        $start_date = Carbon::now()->startOfWeek();
        $end_date = Carbon::now()->endOfWeek();
    }
    else if ($date_range == 'Last Week') {
        $start_date = Carbon::now()->subWeek()->startOfWeek();
        $end_date = Carbon::now()->subWeek()->endOfWeek();
    }
    else if ($date_range == 'This Month') {
        $start_date = Carbon::now()->startOfMonth();
        $end_date = Carbon::now()->endOfMonth();
    }
    else if ($date_range == 'Last Month') {
        $start_date = Carbon::now()->subMonth()->startOfMonth();
        $end_date = Carbon::now()->subMonth()->endOfMonth();
    }
    else {
        // All Time
        if ($lead = Lead::orderBy('created_at', 'asc')->first()) {
            $start_date = Carbon::parse($lead->created_at);
        }
        else {
            $start_date = Carbon::now()->startOfDay();
        }

        $end_date = Carbon::now()->endOfDay();
    }

    return [
        'start_date' => $start_date,
        'end_date' => $end_date,
    ];
}

I'm wondering how I can do this properly so that it will query results using UTC but show monday to sunday in the users timezone, no matter what the user timezone is compared to UTC.

Machavity
  • 30,841
  • 27
  • 92
  • 100
kjdion84
  • 9,552
  • 8
  • 60
  • 87

2 Answers2

0

You can use Laravel helper function config to set timezone. However, this will affects only the request you will receive.

config(['app.timezone' => $timezone]);

If your goal is to change once the timezone and run on every request then what about saving the changed timezone in DB or in a file. Then, write a query for DB or read a file in app/config.php and change the value of index timezone in a file.

Reference ::Change TimeZone dynamically in laravel

Anil Kumar Sahu
  • 567
  • 2
  • 7
  • 27
  • That is terrible because there would be no base timezone to use as a reference (e.g. UTC). Like I said I store all dates in the database in UTC, and use an accessor to convert them to the current user timezone. I figured out my answer, but thanks for trying. – kjdion84 Feb 17 '18 at 15:38
0

I ended up creating separate return properties for local and utc start and end dates.

Heres what my code now looks like:

public static function dateStartEnd($date_range, $date_from, $date_to)
{
    if ($date_range == 'Today') {
        $start_local = Carbon::now(auth()->user()->timezone)->startOfDay();
        $end_local = Carbon::now(auth()->user()->timezone)->endOfDay();
    }
    else if ($date_range == 'Yesterday') {
        $start_local = Carbon::now(auth()->user()->timezone)->subDay()->startOfDay();
        $end_local = Carbon::now(auth()->user()->timezone)->subDay()->endOfDay();
    }
    else if ($date_range == 'This Week') {
        $start_local = Carbon::now(auth()->user()->timezone)->startOfWeek();
        $end_local = Carbon::now(auth()->user()->timezone)->endOfWeek();
    }
    else if ($date_range == 'Last Week') {
        $start_local = Carbon::now(auth()->user()->timezone)->subWeek()->startOfWeek();
        $end_local = Carbon::now(auth()->user()->timezone)->subWeek()->endOfWeek();
    }
    else if ($date_range == 'This Month') {
        $start_local = Carbon::now(auth()->user()->timezone)->startOfMonth();
        $end_local = Carbon::now(auth()->user()->timezone)->endOfMonth();
    }
    else if ($date_range == 'Last Month') {
        $start_local = Carbon::now(auth()->user()->timezone)->subMonth()->startOfMonth();
        $end_local = Carbon::now(auth()->user()->timezone)->subMonth()->endOfMonth();
    }
    else if ($date_range == 'Custom') {
        $start_local = Carbon::parse($date_from, auth()->user()->timezone)->startOfDay();
        $end_local = Carbon::parse($date_to, auth()->user()->timezone)->endOfDay();
    }
    else {
        // All Time
        if ($lead = Lead::orderBy('created_at', 'asc')->first()) {
            $start_local = Carbon::parse($lead->created_at, auth()->user()->timezone);
        }
        else {
            $start_local = Carbon::now(auth()->user()->timezone)->startOfDay();
        }

        $end_local = Carbon::now(auth()->user()->timezone)->endOfDay();
    }

    return [
        'start_local' => $start_local,
        'start_utc' => $start_local->copy()->timezone(config('app.timezone')),
        'end_local' => $end_local,
        'end_utc' => $end_local->copy()->timezone(config('app.timezone')),
    ];
}
kjdion84
  • 9,552
  • 8
  • 60
  • 87