skip to Main Content

Users can set their timezone and we store it in the database. Then we can dynamically change the system timezone on each page load in Middleware or in our AppServiceProvider.

Example: https://stackoverflow.com/a/47938555/5156146

The problem with this is that it messes up our logs. Any logs will be in the user’s local timezone instead of UTC.

How can we set the timezone dynamically for each user while still keeping the timezone correct in our log files?

Currently we use date() and now() in many places throughout my code. I want these to all be set to the user’s timezone but still have any logs stored in UTC.

2

Answers


  1. in Carbon, we can use localization, for example:

    Carbon::now('Asia/Jakarta');
    

    this will generate timestamps based on Jakarta, Indonesia.

    You can store your user’s timezone in the database and access it on user’s controller for the localization, and use your desired timezone for your log.

    here’s a list of supported timezones : PHP Supported Time Zone

    Login or Signup to reply.
  2. Changing PHP’s default timezone will alter the timezone used for the logs. To avoid that, don’t change the default timezone. You can even block the default timezone functions from being used though this might cause errors if you have any code/libraries that uses them. There are various methods to get formatted date & time without changing PHP’s default timezone, using the date() and now() functions are not among them.

    Using pure PHP, you can use the DateTime and DateTimeZone objects:

    $userTz = new DateTimeZone($userTimezoneString);
    $userNow = new DateTime('now', $userTz);
    echo $userNow->format('Y-m-d H:i:s'); // 2023-05-09 12:22:46
    

    There are some date/time libraries available that provide additional options for managing dates. A popular one is the Carbon library (needs to be installed first; for instance, using composer). In fact, Carbon extends off of and adds additional methods and functionality to PHP’s DateTime and other related date/time/timezone classes:

    $userNow = Carbon::now($userTimezoneString);
    $userNow->toDateTimeString(); // 2023-05-09 12:22:46
    

    A third, and in my opinion the most powerful option, is to use the ICU INTL extension (short for Internationalization; the extension needs to be activated in the PHP.ini file but comes bundled with PHP by default). This library is fast and powerful. It used to be disabled by most web hosting early on but has matured and functions in modern PHP are even being deprecated and removed in favor of their INTL equivalents. Most web hosts now have this extension enabled as it’s used by an increasing number of libraries for translation, tokenization, transliteration, formatting, etc.

    $now = new DateTime(); // No timezone required at this step
    
    $userDateFormatter = new IntlDateFormatter(
        $userLocale, // User's locale, such as en_US, en_UK, de_DE, ar_EG, etc.
        IntlDateFormatter::FULL,
        IntlDateFormatter::FULL,
        $userTimezoneString, // User's timezone
        IntlDateFormatter::GREGORIAN
    );
    
    echo $userDateFormatter->format($now);
    // Dienstag, 9. Mai 2023 um 14:22:46 Mitteleuropäische Sommerzeit
    // (Assuming de_DE user locale and Europe/Berlin user timezone)
    

    You saw that correctly, it will even translate to the user’s language as well as use the date/time format commonly expected by users of the region (using the locale variable) and convert the given DateTime object’s information to the given timezone when formatting… all without touching the default timezone. You can use any of the supported locales.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search