Package Information
Documentation

n8n-nodes-city-timezone-lookup
This project provides a custom n8n community node for resolving timezone and
local-time details from either:
- a city and country/region, such as
BucharestandRomania - a latitude and longitude pair, such as
44.43225and26.10626
The node helps workflows normalize location input into reliable timezone data,
including the IANA timezone ID, current local time, GMT offset, DST status, and
lookup metadata. It is useful for scheduling, routing, reporting, reminders,
customer-local notifications, and any automation that needs to understand the
current time for a place.
Table of Contents
- Technologies Used
- How It Works
- Prerequisites
- Installation
- Usage Overview
- Supported Inputs
- Output Fields
- Example Workflow
- Project Structure
- Development
- References
- Troubleshooting
Technologies Used
- n8n - workflow automation platform.
- @n8n/node-cli - local node build,
lint, development, and release tooling. - TypeScript - node implementation language.
- Luxon - local time, offset, and DST
calculation. - city-timezones - city and
region lookup data. - countries-and-timezones
- country code, country name, and timezone metadata.
- @photostructure/tz-lookup
- coordinate to IANA timezone resolution.
- Docker Compose - optional local n8n runtime for loading the node in a container.
How It Works
The City Timezone Lookup node receives one n8n input item and returns one output
item. For each item it:
- Reads the configured city/country fields and optional coordinate fields.
- Uses coordinates first when both latitude and longitude are provided.
- Otherwise resolves the timezone from city and country/region.
- Applies nearest-match fallback only when enabled and only when the match is
unambiguous. - Computes the current local time, GMT offset, offset minutes, and DST status
for the resolved IANA timezone. - Returns the timezone result plus metadata describing how the match was made.
The node also caches successful timezone resolutions during one workflow
execution, so repeated identical locations in the same run do not repeat the
underlying lookup work.
Prerequisites
- Node.js
>=18.10 - npm
>=9 - n8n with community nodes enabled
- git, when installing from source
- Docker and Docker Compose, when using the included local container setup
Installation
Option 1: Install as an n8n community package
Install the package directly with npm:
npm install n8n-nodes-city-timezone-lookup
Or install it from the n8n UI:
- Open n8n.
- Go to Settings -> Community Nodes.
- Select Install.
- Enter
n8n-nodes-city-timezone-lookup. - Restart n8n if your runtime requires it.
- Search for City Timezone Lookup in the workflow editor.
For self-hosted n8n, make sure community packages are enabled:
N8N_COMMUNITY_PACKAGES_ENABLED=true
Option 2: Load the node from this repository with Docker Compose
This repository includes a docker-compose.yaml that mounts the project into
n8n's custom extensions directory.
- Create the environment file:
cp env/n8n.env.example env/n8n.env
Review
env/n8n.envand adjust host, auth, protocol, certificate, and
timezone settings for your environment.Install dependencies and build the node:
npm install
npm run build
- Start n8n:
docker compose up -d
- Open n8n at:
http://localhost:5678
If HTTPS is enabled in env/n8n.env, use the configured HTTPS URL instead.
Option 3: Install locally into an existing n8n custom directory
Use this approach when you already run n8n outside this repository.
git clone https://github.com/tudor555/n8n-nodes-city-timezone-lookup.git
cd n8n-nodes-city-timezone-lookup
npm install
npm run build
Then place or symlink the built package where your n8n instance loads custom
nodes. For many self-hosted setups this is under:
~/.n8n/custom
Restart n8n after adding the package.
Usage Overview
- Add the City Timezone Lookup node to a workflow.
- Connect it after any trigger or data-producing node.
- Configure one of these input modes:
- City mode: set City and Country/Region.
- Coordinate mode: open Additional Options and set both
Latitude (optional) and Longitude (optional).
- Leave Allow Nearest Match enabled when you want safe fallback behavior for
slightly imperfect city or region text. - Execute the workflow and use the output fields in later nodes.
Coordinate lookup takes priority when both latitude and longitude are provided,
even if city and country/region are also filled in.
Supported Inputs
| Field | Type | Required | Description |
|---|---|---|---|
city |
string | Required for city mode | City name to resolve, for example Berlin or Bucharest. |
countryOrRegion |
string | Required for city mode | Country code, country name, or supported alias/region text, for example DE, Germany, US, United States, or Bucuresti. |
latitude |
number | Required for coordinate mode | Latitude from -90 to 90. Must be provided together with longitude. |
longitude |
number | Required for coordinate mode | Longitude from -180 to 180. Must be provided together with latitude. |
nearest |
boolean | Optional | Enables safe fallback matching for city/country lookups. Defaults to true. |
You must provide either both city and countryOrRegion, or both latitude
and longitude.
Output Fields
Successful output always includes the core timezone and local-time fields:
| Field | Type | Description |
|---|---|---|
inputSource |
string | Input path used by the node: cityCountry or coordinates. |
lookupMethod |
string | Resolution method: exactCityCountry, partialCityRegion, cityOnlyFallback, or coordinates. |
timezoneId |
string | IANA timezone identifier, such as Europe/Bucharest. |
localTime |
string | Current local time in the resolved timezone as an ISO timestamp. |
gmtOffset |
string | Current UTC offset, such as +03:00. |
gmtOffsetMinutes |
number | Current UTC offset in minutes. |
isDST |
boolean | Whether daylight saving time is currently active for the timezone. |
timezoneCandidates |
string[] | Timezone IDs considered by the resolver. |
fallbackUsed |
boolean | Whether the result came from fallback logic. |
nearest |
boolean | Whether nearest-match fallback was enabled for the lookup. |
City/country output can also include:
| Field | Type | Description |
|---|---|---|
city |
string | Original city input used for the lookup. |
countryOrRegion |
string | Original country/region input used for the lookup. |
fallbackReason |
string | Reason fallback was used, such as partialCityRegionMatch or countryOrRegionNotMatched. |
matchedLocation |
object | Best matched location with city, country, country code, province, latitude, longitude, and population. |
matchCount |
number | Number of location candidates behind the selected timezone. |
ambiguousMatchesResolvedBy |
string | Present when multiple candidates were accepted because they share one timezone. |
candidateMatches |
object[] | Up to 10 candidate locations considered by the resolver. |
Coordinate output also includes:
| Field | Type | Description |
|---|---|---|
coordinates |
object | The latitude and longitude used for lookup. |
When n8n's Continue On Fail setting is enabled and a lookup fails, the item
returns:
{
"errorMessage": "No timezone match was found for \"Example, Unknown\".",
"failedInput": {
"city": "Example",
"countryOrRegion": "Unknown",
"additionalOptions": {
"nearest": true
}
}
}
Example Workflow
Basic workflow:
- Add a Manual Trigger node.
- Add City Timezone Lookup.
- Set City to
Bucharest. - Set Country/Region to
Romania. - Execute the workflow.
Example successful output:
{
"inputSource": "cityCountry",
"lookupMethod": "exactCityCountry",
"timezoneId": "Europe/Bucharest",
"localTime": "2026-07-19T14:30:00+03:00",
"gmtOffset": "+03:00",
"gmtOffsetMinutes": 180,
"isDST": true,
"fallbackUsed": false,
"timezoneCandidates": ["Europe/Bucharest"],
"city": "Bucharest",
"countryOrRegion": "Romania",
"matchedLocation": {
"city": "Bucharest",
"country": "Romania",
"countryCode": "RO",
"province": "Bucuresti",
"latitude": 44.43225,
"longitude": 26.10626,
"population": 1877155
},
"matchCount": 1,
"candidateMatches": [
{
"city": "Bucharest",
"country": "Romania",
"countryCode": "RO",
"province": "Bucuresti",
"timezoneId": "Europe/Bucharest",
"latitude": 44.43225,
"longitude": 26.10626,
"population": 1877155
}
],
"nearest": true
}
Coordinate example:
{
"inputSource": "coordinates",
"lookupMethod": "coordinates",
"timezoneId": "Europe/Bucharest",
"localTime": "2026-07-19T14:30:00+03:00",
"gmtOffset": "+03:00",
"gmtOffsetMinutes": 180,
"isDST": true,
"timezoneCandidates": ["Europe/Bucharest"],
"fallbackUsed": false,
"coordinates": {
"latitude": 44.43225,
"longitude": 26.10626
},
"nearest": true
}
localTime, gmtOffset, and isDST are computed at workflow execution time,
so these values change depending on when the workflow runs.
Project Structure
.
├── nodes
│ └── CityTimezoneLookup
│ ├── CityTimezoneLookup.node.ts
│ ├── CityTimezoneLookup.node.json
│ ├── cityTimezoneLookup.svg
│ ├── cityTimezoneLookup.dark.svg
│ └── helpers
│ ├── countriesAndTimezones.ts
│ ├── localTime.ts
│ ├── timezoneResolver.ts
│ └── timezoneTypes.ts
├── docs
│ ├── fallbackLogic.md
│ ├── nodeStructure.md
│ ├── performance.md
│ └── testing.md
├── env
│ └── n8n.env.example
├── docker-compose.yaml
├── package.json
├── tsconfig.json
└── README.md
Development
Install dependencies:
npm install
Run n8n with the node loaded for local development:
npm run dev
Build the distributable node:
npm run build
Run lint checks:
npm run lint
Before contributing, read:
- Node structure for the internal organization.
- Fallback logic before changing resolver behavior.
- Performance notes before changing caching or lookup
dependencies. - Testing guidance for the current and future test strategy.
Contribution checklist:
- Keep behavior scoped to the City Timezone Lookup node.
- Update README and docs when input, output, fallback, or installation behavior
changes. - Run
npm run buildandnpm run lintbefore opening a pull request. - Include focused tests when test infrastructure is added.
- Do not commit local n8n runtime data, secrets, or generated environment files.
References
Detailed documentation lives in docs/:
- docs/nodeStructure.md - how the node is organized
internally. - docs/fallbackLogic.md - fallback behavior, safe-match
rules, and error handling. - docs/performance.md - caching and optimization strategy.
- docs/testing.md - guidance for future test setup and
verification.
Related project files:
- package.json - scripts, dependencies, n8n node registration,
and package metadata. - docker-compose.yaml - optional local n8n container setup.
- env/n8n.env.example - example n8n runtime environment.
- CHANGELOG.md - release history.
- LICENSE - MIT license.
Troubleshooting
Node does not appear in n8n
Check:
- The package was installed or mounted in the directory n8n uses for custom
extensions. N8N_COMMUNITY_PACKAGES_ENABLED=trueis set for self-hosted n8n.- The node was built with
npm run build. - n8n was restarted after installation.
Docker Compose starts but n8n cannot load the node
Check:
env/n8n.envexists.- The repository is mounted at
/home/node/.n8n/custom/n8n-nodes-city-timezone-lookup. - Dependencies were installed and
dist/was generated before starting n8n.
Useful commands:
docker compose logs -f
docker compose down
docker compose up -d
Lookup fails for city and country
Check:
- Both City and Country/Region are populated.
- The country value is a country code or recognizable country/region name.
- Allow Nearest Match is enabled if you expect fallback behavior.
- Ambiguous city names may fail when multiple candidates map to different
timezones.
Coordinate lookup fails
Check:
- Both latitude and longitude are provided.
- Latitude is between
-90and90. - Longitude is between
-180and180.