> ## Documentation Index
> Fetch the complete documentation index at: https://cal.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Timezones

> Let a user pick a timezone by searching for a city or a timezone name

Every Cal.com timezone is an [IANA identifier](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) such as `America/Los_Angeles`. [`GET /v2/timezones`](/docs/api-reference/v2/timezones/get-timezones) gives you the list to pick one from: a `city` to show the user, and the `timezone` to store and to send back to us on bookings, event types and schedules.

The endpoint is unauthenticated, and the data changes only when the underlying city database does, so it is safe to cache.

## Searching

`search` matches city names and timezone names, case-insensitively, on any part of the name. It also accepts a complete IANA identifier, such as `America/Los_Angeles`, matched case-insensitively. Identifier searches return the matching alias (when available), followed by cities in that timezone; partial identifiers are not matched:

```bash theme={null}
curl -G 'https://api.cal.com/v2/timezones' --data-urlencode 'search=san francisco'
```

```json theme={null}
{
  "status": "success",
  "data": [
    { "city": "San Francisco", "timezone": "America/Los_Angeles", "pop": 2091036, "country": "United States of America", "region": "California" },
    { "city": "San Francisco de Macoris", "timezone": "America/Santo_Domingo", "pop": 138650.5, "country": "Dominican Republic", "region": "Duarte" },
    { "city": "San Francisco", "timezone": "America/Argentina/Cordoba", "pop": 43231, "country": "Argentina", "region": "Córdoba" },
    { "city": "San Francisco Gotera", "timezone": "America/El_Salvador", "pop": 16152, "country": "El Salvador", "region": "Morazán" }
  ]
}
```

A substring can match several cities, including cities with the same name in different timezones. `?search=valencia` returns both Valencia in Venezuela (`America/Caracas`) and Valencia in Spain (`Europe/Madrid`). Show `city`, `region` and `country` so users can choose their location instead of assuming the first result is correct. Results are ordered by population, most populated first, with one entry per city name and timezone pair; duplicates within the same pair keep the most populated city. Country and region describe that representative city.

Omit `search` to get every city, around 7000 of them. That response is unchanged from before `search` existed, which means it still carries the 48 entries the upstream city database has no timezone for — `{ "city": "Perm", "timezone": null, "pop": 924154 }` and 47 others. `timezone` is therefore nullable on the unfiltered path, and a `null` entry cannot be stored as a scheduling timezone, so filter it out or leave it unselectable in your UI.

`search` never returns one: `?search=perm` gives you Permet in Albania, not Perm.

## Capping the response

A short term matches a lot: `?search=a` is 5,223 entries and 536 KB, which is more than the 425 KB of the whole unfiltered list, so a one-character keystroke costs more than fetching everything once. `limit` caps it, and because results are ordered by relevance the entries you keep are the ones a user is most likely to want:

```bash theme={null}
curl -G 'https://api.cal.com/v2/timezones' --data-urlencode 'search=a' --data-urlencode 'limit=20'
```

`limit` accepts whole numbers from 1 to 250 and applies to both paths. Omit it to get every match, which is what callers got before it existed.

## Searching for a timezone

Users type `PDT` or `Pacific Time` rather than `America/Los_Angeles`, and no city is called either of those. `search` therefore also matches a small set of timezone names, and returns the timezone's own name as the `city`:

```bash theme={null}
curl -G 'https://api.cal.com/v2/timezones' --data-urlencode 'search=PDT'
```

```json theme={null}
{
  "status": "success",
  "data": [{ "city": "Pacific Time - US & Canada", "timezone": "America/Los_Angeles" }]
}
```

`PST`, `Pacific Time`, `Pacific Daylight Time` and `Pacific Standard Time` all resolve to the same entry. The standard and daylight names of a zone are deliberately the same entry, because they are the same IANA timezone.

Abbreviations can name different timezones in different countries. This is a curated alias list, not an exhaustive abbreviation resolver: for example, `CST` selects the US Central entry, and `IST` selects India. Show the returned label and let the user choose their location; use a city name or a complete IANA identifier when the intended timezone is known.

Timezone entries have no `pop`, `country` or `region`, and they come before city matches, because a zone name is the more likely answer when a term matches both: `?search=utc` returns `Coordinated Universal Time` first, then the city of Hutchinson.

## What the response does not contain

There are no abbreviations (`PDT`) and no offsets (`GMT-7`) in the response, and there is nothing to keep in sync when daylight saving starts:

* `America/Los_Angeles` already *means* PDT in summer and PST in winter. Store the identifier and let the user's own platform render the current abbreviation or offset from it.
* An offset is only true for part of the year. `GMT-7` is San Francisco in July and Denver in January.

So `search` accepts abbreviations as *input* — that is what users type — while the stored value stays the identifier.

## Building a timezone picker

1. Call the endpoint with `search` set to what the user typed, debounced.
2. Show `city`, `region` and `country` as the option label when the location fields are present; otherwise show `city` alone.
3. Store `timezone` as the value. That is what you send to Cal.com, and what Cal.com sends back.

Unauthenticated requests are rate limited to 120 per minute per IP — see [Rate limits](/docs/api-reference/v2/introduction#rate-limits) — so debounce the keystrokes rather than calling on each one, and pass `limit` to keep each response small.

Successful responses carry `Cache-Control: public, max-age=86400`. The data only moves when the bundled city database does, which takes a deploy, so a CDN or a browser can hold a response for a day; error responses are not cached. Successful responses omit caller-specific rate-limit headers and `X-Request-Id` so a shared cache cannot replay another caller’s quota or request identifier. Rate limiting still applies to requests that reach the API, and request identifiers remain available in server logs.

The unfiltered list preserves the legacy response: it keeps only the most populated city per name and has no country or region fields. Filtering it in the browser cannot recover same-named cities in other timezones. Use `search` for a picker that needs those alternatives; it searches the full city dataset.
