---
title: "Quiet hours and timezones — Notifications for Laravel | Roundly"
description: "Hold non-urgent mail during each user’s local quiet hours, resolve the timezone, handle DST, and set a default for users without their own."
url: https://roundly-consulting.com/open-source/docs/notifications-for-laravel/quiet-hours
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Notifications for Laravel](https://roundly-consulting.com/open-source/docs/notifications-for-laravel.md)

# Quiet hours and timezones

Quiet hours are local HH:MM times in the user’s own timezone and may cross midnight:

```php
$prefs = Notifications::preferences($user);

$prefs->quietHours('22:00', '07:00');   // local HH:MM, may cross midnight; equal times are refused
$prefs->quietHours(null);               // clears them
$prefs->quietHoursPreference();         // the user's, else notifications.quiet_hours.default, else null

$prefs->timezone('Europe/Bratislava');  // an IANA id; null clears it
$prefs->resolvedTimezone();
```

```php
// config/notifications.php — for users without their own
'quiet_hours' => [
    'enabled' => true,
    'default' => ['start' => '22:00', 'end' => '07:00'],
],
```

- A non-urgent mail created while quiet is held until the window ends (NotificationMailHeld fires).
- Urgent types are never held. Mandatory means “cannot mute”, not “wakes you up”: a mandatory non-urgent type is held.
- A held or trailing mail is checked again at delivery and held again if quiet hours started meanwhile.
- A digest slot inside quiet hours moves to their end.
- DST: a local end that does not exist (spring forward) moves forward (02:30 → 03:30); an ambiguous one takes the first occurrence.
- notifications.quiet\_hours.enabled is the global switch.

## Timezone resolution

The default resolver (notifications.timezone.resolver) takes the first valid IANA id of:

- the recipient’s HasNotificationTimezone::notificationTimezone();
- the stored preference ($prefs->timezone('Europe/Bratislava'));
- the attribute notifications.timezone.attribute (timezone; blank disables it), read only when present in the attributes — safe on strict-mode hosts;
- config('app.timezone').

An invalid id is skipped and logged once per recipient per process; it never throws at delivery. Bind your own ResolvesTimezone to read it elsewhere:

```php
use Illuminate\Database\Eloquent\Model;
use RoundlyConsulting\Notifications\Contracts\ResolvesTimezone;

final class WorkspaceTimezoneResolver implements ResolvesTimezone
{
    public function timezone(Model $recipient): string
    {
        return $recipient->workspace?->timezone ?? config('app.timezone');
    }
}

// config/notifications.php
'timezone' => ['resolver' => App\Notifications\WorkspaceTimezoneResolver::class, 'attribute' => 'timezone'],
```

## Locale

Mail renders in the recipient’s preferredLocale(); inbox titles render in the viewer’s request locale, with a snapshot in the recipient’s locale. There is no separate locale preference.

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/notifications-for-laravel.md)
