# Timezone Middleware

**URL:** <https://discourse.cakephp.org/t/timezone-middleware/10107>\
**Category:** Need Help\
**Created:** [January 24, 2022, 10:43am UTC](https://discourse.cakephp.org/t/timezone-middleware/10107 "2022-01-24T10:43:55Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![mvojwe](https://avatars.discourse-cdn.com/v4/letter/m/9d8465/32.png) [@mvojwe](https://discourse.cakephp.org/u/mvojwe)\
**Post date:** [January 24, 2022, 10:43am UTC](https://discourse.cakephp.org/t/timezone-middleware/10107/1 "2022-01-24T10:43:55Z")

</div>

I’m trying to build an application in which everyone can see each other favorite datetime but in their own timezone, so I have the following structure:

- Table users: email, password, favorite\_date (datetime), timezone (string, e.g: ‘UTC’, ‘Europe/Madrid’, ‘America/Argentina/Buenos\_Aires’, etc)
- File config/App.php: defaultTimezone UTC
- File templates/Users/view:

> \<?= $this-\>Time-\>format($user-\>favorite\_date, null, false, $this-\>Identity-\>get('timezone')); ?\>

- File templates/Users/add:

> \<?= $this-\>Form-\>control('favorite\_date', ['type' =\> 'datetime', 'default' =\> new FrozenTime('now', $this-\>Identity-\>get('timezone'))]); ?\>

- File templates/Users/edit:

> \<?= $this-\>Form-\>control('favorite\_date', ['type' =\> 'datetime', 'value' =\> $user-\>fecha\_ingreso-\>setTimezone($this-\>Identity-\>get('timezone'))]); ?\>

- File src/Controller/UsersController/add and src/Controller/UsersController/add:

> if ($this-\>request-\>is(‘post’)) {  
> $data = $this-\>request-\>getData();  
> $data[‘favorite\_date’] = new FrozenTime($data[“favorite\_date”], $this-\>Authentication-\>getIdentity()-\>get(‘timezone’));  
> $user = $this-\>Users-\>patchEntity($user, $data);  
> $this-\>Tropas-\>save($user)  
> }

This is working fine (showing everything in the user timezone but saving it as UTC), but now I’m trying to keep my code DRY.

I’ve been reading [Date & Time - 4.x](https://book.cakephp.org/4/en/core-libraries/time.html) and [Internationalization & Localization 4.x](https://book.cakephp.org/4/en/core-libraries/internationalization-and-localization.html#converting-request-data-from-the-user-s-timezone) and then I implemented the DateTimeMiddleware from the example,

- File src/Controllers/Middleware/DateTimeMiddleware.php:

> class DateTimeMiddleware  
> implements MiddlewareInterface  
> {  
> public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface  
> {  
> $user = $request-\>getAttribute(‘identity’);  
> if ($user) {  
> TypeFactory::build(‘datetime’)  
> -\>useLocaleParser()  
> -\>setUserTimezone($user-\>timezone);  
> }  
> return $handler-\>handle($request);  
> }  
> }

Now, I’m not sure of which part of my previous code I should be able to remove adding this middleware since I dont fully understand how this works. Can I get some help?

---

<div class="post-metadata">

**Author:** ![ndm](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.cakephp.org/ndm/32/2234_2.png) [@ndm](https://discourse.cakephp.org/u/ndm)\
**Post date:** [January 25, 2022, 4:51pm UTC](https://discourse.cakephp.org/t/timezone-middleware/10107/2 "2022-01-25T16:51:19Z")

</div>

When request data is being parsed/coverted in the marshalling stage (this happens when you patch or create an entity with data), the user timezone config is used for constructing the datetime object from the request data, and then it is converted to the default timezone (which should equal your app/PHP default timezone at the time of the database type object being constructed).

So say your type’s user timezone is `Europe/Madrid`, and your app/PHP default timezone is `UTC`, the flow would be:

1. request data is marshalled
2. date is parsed/interpreted in user timezone (`Europe/Madrid`)
3. date is converted to default timezone (`UTC`)
4. date is converted to database timezone if configured (`\Cake\Database\Type\DateTimeType::setDatabaseTimezone()`)

When reading data from the database, the user timezone config is not involved, as the database type object doesn’t know what you’re going to do with the data. Instead the received value is created using the database timezone if configured, and then converted to the default timezone, so:

1. date is read from database
2. date is parsed/interpreted in database timezone if configured, otherwise default timezone (`UTC`)
3. date is converted to default timezone (`UTC`)

So, what you should be able to drop from your code is passing the value and setting the timezone in your `edit.php` template, and the creation and injection of the datetime object in your controller’s `add()` and `edit()` methods.

The `add.php` template would still need it for the default value, as creating datetime objects is only aware of the default timezone. The `view.php` template would also still need it, as what you get from the database is not being converted into the user timezone (since you’re using the time helper, you could use the helper’s unfortunaltey undocumented `outputTimezone` option in case you want to apply the user timezone to all usages of the helper).

---

<div class="post-metadata">

**Author:** ![MDebus](https://avatars.discourse-cdn.com/v4/letter/m/b77776/32.png) [@MDebus](https://discourse.cakephp.org/u/MDebus)\
**Post date:** [January 10, 2024, 4:03pm UTC](https://discourse.cakephp.org/t/timezone-middleware/10107/3 "2024-01-10T16:03:27Z")

</div>

Hey guys,

i have some questions to this old topic, because i have several problems.  
My application’s default timezone is UTC, serverside and in database columns.  
I added a DateTimeMiddleware like described in the documentations:

```auto
class DatetimeMiddleware implements MiddlewareInterface {
    
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface {
        
        $tenant = $request->getAttribute('tenant');
        if ($tenant) {
            // set timezone from tenant's config, e.g. 'Europe/Berlin'
            $timezone = $tenant->config->timezone? $tenant->config->timezone: Configure::read('App.defaultTimezone');
            
            TypeFactory::build('datetime')
                //->useLocaleParser()
                ->setUserTimezone($timezone);
        } 

        return $handler->handle($request);
    }
}

```

Now, when i receive some data with timezone “Europe/Berlin” from API or POST method, the timezone is translated to UTC and saved to database.  
How can I output this data in the frontend in the correct tenent-based time zone?  
I don’t want to output it several times with code like that:

```auto
$date->i18nFormat(\IntlDateFormatter::FULL, 'Europe/Berlin')

```

Is it possible to do this in a more central way?

I tried in the AppView.php, but it doesn’t work:

```auto
        $tenant = $this->getRequest()->getAttribute('tenant');
        $timezone = $tenant->config->timezone? $tenant->config->timezone: Configure::read('App.defaultTimezone');
        $this->loadHelper('Time', ['outputTimezone' => $timezone]);

```

---

<div class="post-metadata">

**Author:** ![MDebus](https://avatars.discourse-cdn.com/v4/letter/m/b77776/32.png) [@MDebus](https://discourse.cakephp.org/u/MDebus)\
**Post date:** [January 11, 2024, 9:52am UTC](https://discourse.cakephp.org/t/timezone-middleware/10107/4 "2024-01-11T09:52:30Z")

</div>

OK, I think I did it.

Of course i have to use the TimeHelper in view, when you set the timezone attribute.  
Unfortunately, this is not possible when outputting the direct FrozenTime type.

```auto
$this->Time->i18nFormat($date, [\IntlDateFormatter::NONE, \IntlDateFormatter::SHORT])

```

---

<div class="post-metadata">

**Author:** ![MDebus](https://avatars.discourse-cdn.com/v4/letter/m/b77776/32.png) [@MDebus](https://discourse.cakephp.org/u/MDebus)\
**Post date:** [January 12, 2024, 1:34pm UTC](https://discourse.cakephp.org/t/timezone-middleware/10107/5 "2024-01-12T13:34:21Z")

</div>

Please, i need help againg…

Now that I’m working with UTC on the server side and passing the data to the view, I’m encountering issues again with my form controls. I can’t convert the timezone to “Europe/Berlin” or anything else. There is no option for form helper.

So here is my question:

What is best practise in CakePHP 4.X for international timezones?  
I think in database you have to save the time in UTC, right?

But what about the server side, i.e. the defaultTimezone of the PHP settings?

---

<div class="post-metadata">

**Author:** ![Zuluru](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.cakephp.org/zuluru/32/1230_2.png) [@Zuluru](https://discourse.cakephp.org/u/Zuluru)\
**Post date:** [January 12, 2024, 2:57pm UTC](https://discourse.cakephp.org/t/timezone-middleware/10107/6 "2024-01-12T14:57:42Z")

</div>

My `config/app.php` configures both `App.timezone.name` and `Datasources.default.timezone` to the name of the timezone, and then `config/bootstrap.php` does `date_default_timezone_set(Configure::read('App.timezone.name'));`. I don’t think there’s anything else required. Everything is stored in the database as UTC, and is converted to the local timezone when read back out into `FrozenTime` objects, so there’s no need for views to do anything at all with the timezone.

---

<div class="post-metadata">

**Author:** ![mvojwe](https://avatars.discourse-cdn.com/v4/letter/m/9d8465/32.png) [@mvojwe](https://discourse.cakephp.org/u/mvojwe)\
**Post date:** [January 12, 2024, 3:38pm UTC](https://discourse.cakephp.org/t/timezone-middleware/10107/7 "2024-01-12T15:38:18Z")

</div>

I don’t know about best practices in CakePHP but I also save everything in UTC. In the form control you can set the option timezone for datetime fields:

\<?= $this-\>Forms-\>control('date', ['type' =\> 'datetime', 'default' =\> 'now', 'timezone' =\> $this-\>Identity-\>get('timezone')]); ?\>
