Files
weltze.it/zones.js
2025-10-13 11:25:20 -06:00

313 lines
17 KiB
JavaScript

// Principal cities sourced from https://en.wikipedia.org/wiki/List_of_UTC_offsets
const PRINCIPAL_CITY_DATA = [
{ name: 'Honolulu, United States', country: 'United States', timeZone: 'Pacific/Honolulu' },
{ name: 'Anchorage, United States', country: 'United States', timeZone: 'America/Anchorage' },
{ name: 'Los Angeles, United States', country: 'United States', timeZone: 'America/Los_Angeles' },
{ name: 'Vancouver, Canada', country: 'Canada', timeZone: 'America/Vancouver' },
{ name: 'Tijuana, Mexico', country: 'Mexico', timeZone: 'America/Tijuana' },
{ name: 'Denver, United States', country: 'United States', timeZone: 'America/Denver' },
{ name: 'Calgary, Canada', country: 'Canada', timeZone: 'America/Edmonton' },
{ name: 'Ciudad Juárez, Mexico', country: 'Mexico', timeZone: 'America/Ciudad_Juarez' },
{ name: 'Mexico City, Mexico', country: 'Mexico', timeZone: 'America/Mexico_City' },
{ name: 'Chicago, United States', country: 'United States', timeZone: 'America/Chicago' },
{ name: 'Guatemala City, Guatemala', country: 'Guatemala', timeZone: 'America/Guatemala' },
{ name: 'Tegucigalpa, Honduras', country: 'Honduras', timeZone: 'America/Tegucigalpa' },
{ name: 'Winnipeg, Canada', country: 'Canada', timeZone: 'America/Winnipeg' },
{ name: 'San José, Costa Rica', country: 'Costa Rica', timeZone: 'America/Costa_Rica' },
{ name: 'San Salvador, El Salvador', country: 'El Salvador', timeZone: 'America/El_Salvador' },
{ name: 'New York, United States', country: 'United States', timeZone: 'America/New_York' },
{ name: 'Toronto, Canada', country: 'Canada', timeZone: 'America/Toronto' },
{ name: 'Havana, Cuba', country: 'Cuba', timeZone: 'America/Havana' },
{ name: 'Lima, Peru', country: 'Peru', timeZone: 'America/Lima' },
{ name: 'Bogotá, Colombia', country: 'Colombia', timeZone: 'America/Bogota' },
{ name: 'Kingston, Jamaica', country: 'Jamaica', timeZone: 'America/Jamaica' },
{ name: 'Quito, Ecuador', country: 'Ecuador', timeZone: 'America/Guayaquil' },
{ name: 'Santiago, Chile', country: 'Chile', timeZone: 'America/Santiago' },
{ name: 'Santo Domingo, Dominican Republic', country: 'Dominican Republic', timeZone: 'America/Santo_Domingo' },
{ name: 'Manaus, Brazil', country: 'Brazil', timeZone: 'America/Manaus' },
{ name: 'Caracas, Venezuela', country: 'Venezuela', timeZone: 'America/Caracas' },
{ name: 'La Paz, Bolivia', country: 'Bolivia', timeZone: 'America/La_Paz' },
{ name: 'Halifax, Canada', country: 'Canada', timeZone: 'America/Halifax' },
{ name: 'St. John\'s, Canada', country: 'Canada', timeZone: 'America/St_Johns' },
{ name: 'São Paulo, Brazil', country: 'Brazil', timeZone: 'America/Sao_Paulo' },
{ name: 'Buenos Aires, Argentina', country: 'Argentina', timeZone: 'America/Argentina/Buenos_Aires' },
{ name: 'Montevideo, Uruguay', country: 'Uruguay', timeZone: 'America/Montevideo' },
{ name: 'London, United Kingdom', country: 'United Kingdom', timeZone: 'Europe/London' },
{ name: 'Dublin, Ireland', country: 'Ireland', timeZone: 'Europe/Dublin' },
{ name: 'Lisbon, Portugal', country: 'Portugal', timeZone: 'Europe/Lisbon' },
{ name: 'Abidjan, Côte d\'Ivoire', country: 'Côte d\'Ivoire', timeZone: 'Africa/Abidjan' },
{ name: 'Accra, Ghana', country: 'Ghana', timeZone: 'Africa/Accra' },
{ name: 'Dakar, Senegal', country: 'Senegal', timeZone: 'Africa/Dakar' },
{ name: 'Berlin, Germany', country: 'Germany', timeZone: 'Europe/Berlin' },
{ name: 'Frankfurt, Germany', country: 'Germany', timeZone: 'Europe/Berlin' },
{ name: 'Rome, Italy', country: 'Italy', timeZone: 'Europe/Rome' },
{ name: 'Stockholm, Sweden', country: 'Sweden', timeZone: 'Europe/Stockholm' },
{ name: 'Paris, France', country: 'France', timeZone: 'Europe/Paris' },
{ name: 'Madrid, Spain', country: 'Spain', timeZone: 'Europe/Madrid' },
{ name: 'Warsaw, Poland', country: 'Poland', timeZone: 'Europe/Warsaw' },
{ name: 'Lagos, Nigeria', country: 'Nigeria', timeZone: 'Africa/Lagos' },
{ name: 'Kinshasa, DR Congo', country: 'Democratic Republic of the Congo', timeZone: 'Africa/Kinshasa' },
{ name: 'Algiers, Algeria', country: 'Algeria', timeZone: 'Africa/Algiers' },
{ name: 'Casablanca, Morocco', country: 'Morocco', timeZone: 'Africa/Casablanca' },
{ name: 'Athens, Greece', country: 'Greece', timeZone: 'Europe/Athens' },
{ name: 'Bucharest, Romania', country: 'Romania', timeZone: 'Europe/Bucharest' },
{ name: 'Cairo, Egypt', country: 'Egypt', timeZone: 'Africa/Cairo' },
{ name: 'Helsinki, Finland', country: 'Finland', timeZone: 'Europe/Helsinki' },
{ name: 'Jerusalem, Israel', country: 'Israel', timeZone: 'Asia/Jerusalem' },
{ name: 'Johannesburg, South Africa', country: 'South Africa', timeZone: 'Africa/Johannesburg' },
{ name: 'Khartoum, Sudan', country: 'Sudan', timeZone: 'Africa/Khartoum' },
{ name: 'Kyiv, Ukraine', country: 'Ukraine', timeZone: 'Europe/Kyiv' },
{ name: 'Riga, Latvia', country: 'Latvia', timeZone: 'Europe/Riga' },
{ name: 'Sofia, Bulgaria', country: 'Bulgaria', timeZone: 'Europe/Sofia' },
{ name: 'Moscow, Russia', country: 'Russia', timeZone: 'Europe/Moscow' },
{ name: 'Istanbul, Türkiye', country: 'Türkiye', timeZone: 'Europe/Istanbul' },
{ name: 'Riyadh, Saudi Arabia', country: 'Saudi Arabia', timeZone: 'Asia/Riyadh' },
{ name: 'Baghdad, Iraq', country: 'Iraq', timeZone: 'Asia/Baghdad' },
{ name: 'Addis Ababa, Ethiopia', country: 'Ethiopia', timeZone: 'Africa/Addis_Ababa' },
{ name: 'Doha, Qatar', country: 'Qatar', timeZone: 'Asia/Qatar' },
{ name: 'Nairobi, Kenya', country: 'Kenya', timeZone: 'Africa/Nairobi' },
{ name: 'Kuwait City, Kuwait', country: 'Kuwait', timeZone: 'Asia/Kuwait' },
{ name: 'Tehran, Iran', country: 'Iran', timeZone: 'Asia/Tehran' },
{ name: 'Dubai, United Arab Emirates', country: 'United Arab Emirates', timeZone: 'Asia/Dubai' },
{ name: 'Baku, Azerbaijan', country: 'Azerbaijan', timeZone: 'Asia/Baku' },
{ name: 'Tbilisi, Georgia', country: 'Georgia', timeZone: 'Asia/Tbilisi' },
{ name: 'Yerevan, Armenia', country: 'Armenia', timeZone: 'Asia/Yerevan' },
{ name: 'Samara, Russia', country: 'Russia', timeZone: 'Europe/Samara' },
{ name: 'Kabul, Afghanistan', country: 'Afghanistan', timeZone: 'Asia/Kabul' },
{ name: 'Karachi, Pakistan', country: 'Pakistan', timeZone: 'Asia/Karachi' },
{ name: 'Astana, Kazakhstan', country: 'Kazakhstan', timeZone: 'Asia/Almaty' },
{ name: 'Tashkent, Uzbekistan', country: 'Uzbekistan', timeZone: 'Asia/Tashkent' },
{ name: 'Yekaterinburg, Russia', country: 'Russia', timeZone: 'Asia/Yekaterinburg' },
{ name: 'Delhi, India', country: 'India', timeZone: 'Asia/Kolkata' },
{ name: 'Mumbai, India', country: 'India', timeZone: 'Asia/Kolkata' },
{ name: 'Colombo, Sri Lanka', country: 'Sri Lanka', timeZone: 'Asia/Colombo' },
{ name: 'Kathmandu, Nepal', country: 'Nepal', timeZone: 'Asia/Kathmandu' },
{ name: 'Dhaka, Bangladesh', country: 'Bangladesh', timeZone: 'Asia/Dhaka' },
{ name: 'Omsk, Russia', country: 'Russia', timeZone: 'Asia/Omsk' },
{ name: 'Bishkek, Kyrgyzstan', country: 'Kyrgyzstan', timeZone: 'Asia/Bishkek' },
{ name: 'Yangon, Myanmar', country: 'Myanmar', timeZone: 'Asia/Yangon' },
{ name: 'Jakarta, Indonesia', country: 'Indonesia', timeZone: 'Asia/Jakarta' },
{ name: 'Ho Chi Minh City, Vietnam', country: 'Vietnam', timeZone: 'Asia/Ho_Chi_Minh' },
{ name: 'Bangkok, Thailand', country: 'Thailand', timeZone: 'Asia/Bangkok' },
{ name: 'Krasnoyarsk, Russia', country: 'Russia', timeZone: 'Asia/Krasnoyarsk' },
{ name: 'Shanghai, China', country: 'China', timeZone: 'Asia/Shanghai' },
{ name: 'Taipei, Taiwan', country: 'Taiwan', timeZone: 'Asia/Taipei' },
{ name: 'Hong Kong, China', country: 'China', timeZone: 'Asia/Hong_Kong' },
{ name: 'Kuala Lumpur, Malaysia', country: 'Malaysia', timeZone: 'Asia/Kuala_Lumpur' },
{ name: 'Singapore, Singapore', country: 'Singapore', timeZone: 'Asia/Singapore' },
{ name: 'Perth, Australia', country: 'Australia', timeZone: 'Australia/Perth' },
{ name: 'Manila, Philippines', country: 'Philippines', timeZone: 'Asia/Manila' },
{ name: 'Makassar, Indonesia', country: 'Indonesia', timeZone: 'Asia/Makassar' },
{ name: 'Irkutsk, Russia', country: 'Russia', timeZone: 'Asia/Irkutsk' },
{ name: 'Tokyo, Japan', country: 'Japan', timeZone: 'Asia/Tokyo' },
{ name: 'Seoul, South Korea', country: 'South Korea', timeZone: 'Asia/Seoul' },
{ name: 'Pyongyang, North Korea', country: 'North Korea', timeZone: 'Asia/Pyongyang' },
{ name: 'Jayapura, Indonesia', country: 'Indonesia', timeZone: 'Asia/Jayapura' },
{ name: 'Chita, Russia', country: 'Russia', timeZone: 'Asia/Chita' },
{ name: 'Adelaide, Australia', country: 'Australia', timeZone: 'Australia/Adelaide' },
{ name: 'Sydney, Australia', country: 'Australia', timeZone: 'Australia/Sydney' },
{ name: 'Melbourne, Australia', country: 'Australia', timeZone: 'Australia/Melbourne' },
{ name: 'Brisbane, Australia', country: 'Australia', timeZone: 'Australia/Brisbane' },
{ name: 'Port Moresby, Papua New Guinea', country: 'Papua New Guinea', timeZone: 'Pacific/Port_Moresby' },
{ name: 'Vladivostok, Russia', country: 'Russia', timeZone: 'Asia/Vladivostok' },
{ name: 'Nouméa, New Caledonia', country: 'New Caledonia', timeZone: 'Pacific/Noumea' },
{ name: 'Auckland, New Zealand', country: 'New Zealand', timeZone: 'Pacific/Auckland' },
{ name: 'Suva, Fiji', country: 'Fiji', timeZone: 'Pacific/Fiji' },
{ name: 'Petropavlovsk-Kamchatsky, Russia', country: 'Russia', timeZone: 'Asia/Kamchatka' }
];
// Additional curated list to provide broader coverage beyond the principal cities list.
const ADDITIONAL_CITY_DATA = [
{ name: 'Amsterdam, Netherlands', country: 'Netherlands', timeZone: 'Europe/Amsterdam', keywords: ['ams', 'holland', 'nl'] },
{ name: 'Auckland, New Zealand', country: 'New Zealand', timeZone: 'Pacific/Auckland' },
{ name: 'Bangkok, Thailand', country: 'Thailand', timeZone: 'Asia/Bangkok', keywords: ['thai'] },
{ name: 'Barcelona, Spain', country: 'Spain', timeZone: 'Europe/Madrid', keywords: ['catalonia', 'esp'] },
{ name: 'Beijing, China', country: 'China', timeZone: 'Asia/Shanghai', keywords: ['cn'] },
{ name: 'Berlin, Germany', country: 'Germany', timeZone: 'Europe/Berlin', keywords: ['de'] },
{ name: 'Bogotá, Colombia', country: 'Colombia', timeZone: 'America/Bogota', keywords: ['co'] },
{ name: 'Boston, United States', country: 'United States', timeZone: 'America/New_York', keywords: ['est'] },
{ name: 'Cape Town, South Africa', country: 'South Africa', timeZone: 'Africa/Johannesburg', keywords: ['cpt'] },
{ name: 'Copenhagen, Denmark', country: 'Denmark', timeZone: 'Europe/Copenhagen', keywords: ['dk'] },
{ name: 'Dubai, United Arab Emirates', country: 'United Arab Emirates', timeZone: 'Asia/Dubai', keywords: ['uae'] },
{ name: 'Dublin, Ireland', country: 'Ireland', timeZone: 'Europe/Dublin', keywords: ['ie'] },
{ name: 'Frankfurt, Germany', country: 'Germany', timeZone: 'Europe/Berlin', keywords: ['fra'] },
{ name: 'Hong Kong, China', country: 'China', timeZone: 'Asia/Hong_Kong', keywords: ['hk'] },
{ name: 'Istanbul, Türkiye', country: 'Türkiye', timeZone: 'Europe/Istanbul', keywords: ['istanbul'] },
{ name: 'Jakarta, Indonesia', country: 'Indonesia', timeZone: 'Asia/Jakarta', keywords: ['id'] },
{ name: 'Johannesburg, South Africa', country: 'South Africa', timeZone: 'Africa/Johannesburg', keywords: ['za'] },
{ name: 'Kuala Lumpur, Malaysia', country: 'Malaysia', timeZone: 'Asia/Kuala_Lumpur', keywords: ['my'] },
{ name: 'Lisbon, Portugal', country: 'Portugal', timeZone: 'Europe/Lisbon', keywords: ['pt'] },
{ name: 'London, United Kingdom', country: 'United Kingdom', timeZone: 'Europe/London', keywords: ['uk', 'gb', 'gmt'] },
{ name: 'Los Angeles, United States', country: 'United States', timeZone: 'America/Los_Angeles', keywords: ['la', 'pst'] },
{ name: 'Mexico City, Mexico', country: 'Mexico', timeZone: 'America/Mexico_City', keywords: ['mx', 'cdmx'] },
{ name: 'Miami, United States', country: 'United States', timeZone: 'America/New_York', keywords: ['florida'] },
{ name: 'Mumbai, India', country: 'India', timeZone: 'Asia/Kolkata', keywords: ['in', 'bombay'] },
{ name: 'New York, United States', country: 'United States', timeZone: 'America/New_York', keywords: ['nyc'] },
{ name: 'Oslo, Norway', country: 'Norway', timeZone: 'Europe/Oslo', keywords: ['no'] },
{ name: 'Paris, France', country: 'France', timeZone: 'Europe/Paris', keywords: ['fr'] },
{ name: 'Reykjavík, Iceland', country: 'Iceland', timeZone: 'Atlantic/Reykjavik', keywords: ['iceland'] },
{ name: 'San Francisco, United States', country: 'United States', timeZone: 'America/Los_Angeles', keywords: ['sf', 'bay'] },
{ name: 'São Paulo, Brazil', country: 'Brazil', timeZone: 'America/Sao_Paulo', keywords: ['br'] },
{ name: 'Singapore, Singapore', country: 'Singapore', timeZone: 'Asia/Singapore', keywords: ['sg'] },
{ name: 'Stockholm, Sweden', country: 'Sweden', timeZone: 'Europe/Stockholm', keywords: ['se'] },
{ name: 'Sydney, Australia', country: 'Australia', timeZone: 'Australia/Sydney', keywords: ['au'] },
{ name: 'Tokyo, Japan', country: 'Japan', timeZone: 'Asia/Tokyo', keywords: ['jp'] },
{ name: 'Toronto, Canada', country: 'Canada', timeZone: 'America/Toronto', keywords: ['ca'] },
{ name: 'Vienna, Austria', country: 'Austria', timeZone: 'Europe/Vienna', keywords: ['at'] },
{ name: 'Warsaw, Poland', country: 'Poland', timeZone: 'Europe/Warsaw', keywords: ['pl'] },
{ name: 'Zurich, Switzerland', country: 'Switzerland', timeZone: 'Europe/Zurich', keywords: ['ch'] }
];
function deduplicateByKey(list) {
const map = new Map();
list.forEach((entry) => {
const key = `${entry.name.toLowerCase()}|${entry.timeZone}`;
const keywords = Array.isArray(entry.keywords) ? entry.keywords : [];
if (!map.has(key)) {
map.set(key, {
...entry,
keywords
});
} else {
const existing = map.get(key);
const mergedKeywords = new Set([...(existing.keywords || []), ...keywords]);
existing.keywords = Array.from(mergedKeywords);
if (!existing.country && entry.country) {
existing.country = entry.country;
}
}
});
return Array.from(map.values());
}
const RAW_TIMEZONE_DATA = deduplicateByKey([...PRINCIPAL_CITY_DATA, ...ADDITIONAL_CITY_DATA]);
const COUNTRY_TRANSLATIONS = {
Afghanistan: 'Afghanistan',
Algeria: 'Algerien',
Argentina: 'Argentinien',
Armenia: 'Armenien',
Australia: 'Australien',
Austria: 'Österreich',
Azerbaijan: 'Aserbaidschan',
Bangladesh: 'Bangladesch',
Bolivia: 'Bolivien',
Brazil: 'Brasilien',
Bulgaria: 'Bulgarien',
Canada: 'Kanada',
Chile: 'Chile',
China: 'China',
Colombia: 'Kolumbien',
'Costa Rica': 'Costa Rica',
Cuba: 'Kuba',
"Côte d'Ivoire": 'Elfenbeinküste',
'Democratic Republic of the Congo': 'Demokratische Republik Kongo',
Denmark: 'Dänemark',
'Dominican Republic': 'Dominikanische Republik',
Ecuador: 'Ecuador',
Egypt: 'Ägypten',
'El Salvador': 'El Salvador',
Ethiopia: 'Äthiopien',
Fiji: 'Fidschi',
Finland: 'Finnland',
France: 'Frankreich',
Georgia: 'Georgien',
Germany: 'Deutschland',
Ghana: 'Ghana',
Greece: 'Griechenland',
Guatemala: 'Guatemala',
Honduras: 'Honduras',
Iceland: 'Island',
India: 'Indien',
Indonesia: 'Indonesien',
Iran: 'Iran',
Iraq: 'Irak',
Ireland: 'Irland',
Israel: 'Israel',
Italy: 'Italien',
Jamaica: 'Jamaika',
Japan: 'Japan',
Kazakhstan: 'Kasachstan',
Kenya: 'Kenia',
Kuwait: 'Kuwait',
Kyrgyzstan: 'Kirgisistan',
Latvia: 'Lettland',
Malaysia: 'Malaysia',
Mexico: 'Mexiko',
Morocco: 'Marokko',
Myanmar: 'Myanmar',
Nepal: 'Nepal',
Netherlands: 'Niederlande',
'New Caledonia': 'Neukaledonien',
'New Zealand': 'Neuseeland',
Nigeria: 'Nigeria',
'North Korea': 'Nordkorea',
Norway: 'Norwegen',
Pakistan: 'Pakistan',
'Papua New Guinea': 'Papua-Neuguinea',
Peru: 'Peru',
Philippines: 'Philippinen',
Poland: 'Polen',
Portugal: 'Portugal',
Qatar: 'Katar',
Romania: 'Rumänien',
Russia: 'Russland',
'Saudi Arabia': 'Saudi-Arabien',
Senegal: 'Senegal',
Singapore: 'Singapur',
'South Africa': 'Südafrika',
'South Korea': 'Südkorea',
Spain: 'Spanien',
'Sri Lanka': 'Sri Lanka',
Sudan: 'Sudan',
Sweden: 'Schweden',
Switzerland: 'Schweiz',
Taiwan: 'Taiwan',
Thailand: 'Thailand',
Türkiye: 'Türkei',
Ukraine: 'Ukraine',
'United Arab Emirates': 'Vereinigte Arabische Emirate',
'United Kingdom': 'Vereinigtes Königreich',
'United States': 'Vereinigte Staaten',
Uruguay: 'Uruguay',
Uzbekistan: 'Usbekistan',
Venezuela: 'Venezuela',
Vietnam: 'Vietnam'
};
function translateCountry(country) {
return COUNTRY_TRANSLATIONS[country] || country;
}
function addGermanKeywordVariants(keywords, germanValue) {
const variants = new Set(keywords);
const lower = germanValue.toLowerCase();
variants.add(lower);
variants.add(
lower
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
);
return Array.from(variants);
}
const TIMEZONE_DATA = RAW_TIMEZONE_DATA.map((entry) => {
const translatedCountry = translateCountry(entry.country);
const city = entry.name.split(',')[0].trim();
const baseKeywords = Array.isArray(entry.keywords) ? entry.keywords : [];
const keywordsWithCountries = addGermanKeywordVariants(
addGermanKeywordVariants(baseKeywords, entry.country),
translatedCountry
);
return {
...entry,
name: `${city}, ${translatedCountry}`,
country: translatedCountry,
keywords: keywordsWithCountries
};
});
// Provide a sorted copy for deterministic rendering.
const SORTED_TIMEZONE_DATA = TIMEZONE_DATA.slice().sort((a, b) => a.name.localeCompare(b.name));