apps/recallassess/recallassess-api/src/api/shared/timezone/company-timezone.service.ts
Company columns used to resolve the effective IANA zone (no separate DB company_timezone).
Properties |
|
| country |
country:
|
Type : string | null
|
| Optional |
| preferred_timezone |
preferred_timezone:
|
Type : string | null
|
| Optional |
import { Injectable } from "@nestjs/common";
/**
* Maps ISO 3166-1 alpha-2 country codes to a primary IANA timezone.
* Used to derive company timezone from Company.country when preferred_timezone is not set.
* Source: IANA tzdb / common conventions (one primary zone per country where applicable).
*
* Keep in sync with libs/recallassess/shared-ng/src/lib/utils/company-timezone.utils.ts
*/
const COUNTRY_TO_TIMEZONE: Record<string, string> = {
AE: "Asia/Dubai",
AU: "Australia/Sydney",
IN: "Asia/Kolkata",
US: "America/New_York",
GB: "Europe/London",
UK: "Europe/London",
DE: "Europe/Berlin",
FR: "Europe/Paris",
CA: "America/Toronto",
BR: "America/Sao_Paulo",
JP: "Asia/Tokyo",
CN: "Asia/Shanghai",
SG: "Asia/Singapore",
HK: "Asia/Hong_Kong",
MY: "Asia/Kuala_Lumpur",
SA: "Asia/Riyadh",
EG: "Africa/Cairo",
ZA: "Africa/Johannesburg",
NG: "Africa/Lagos",
KE: "Africa/Nairobi",
RU: "Europe/Moscow",
NL: "Europe/Amsterdam",
ES: "Europe/Madrid",
IT: "Europe/Rome",
CH: "Europe/Zurich",
SE: "Europe/Stockholm",
PL: "Europe/Warsaw",
TR: "Europe/Istanbul",
PK: "Asia/Karachi",
BD: "Asia/Dhaka",
ID: "Asia/Jakarta",
TH: "Asia/Bangkok",
VN: "Asia/Ho_Chi_Minh",
PH: "Asia/Manila",
KR: "Asia/Seoul",
NZ: "Pacific/Auckland",
MX: "America/Mexico_City",
AR: "America/Argentina/Buenos_Aires",
CL: "America/Santiago",
CO: "America/Bogota",
PT: "Europe/Lisbon",
IE: "Europe/Dublin",
BE: "Europe/Brussels",
AT: "Europe/Vienna",
NO: "Europe/Oslo",
DK: "Europe/Copenhagen",
FI: "Europe/Helsinki",
GR: "Europe/Athens",
IL: "Asia/Jerusalem",
QA: "Asia/Qatar",
KW: "Asia/Kuwait",
BH: "Asia/Bahrain",
OM: "Asia/Muscat",
JO: "Asia/Amman",
LB: "Asia/Beirut",
SY: "Asia/Damascus",
IQ: "Asia/Baghdad",
IR: "Asia/Tehran",
};
const DEFAULT_TIMEZONE = "UTC";
/**
* Returns the primary IANA timezone for a country code.
* @param countryCode ISO 3166-1 alpha-2 (e.g. "AE", "US"). Case-insensitive.
* @returns IANA timezone string (e.g. "Asia/Dubai") or "UTC" if unknown/missing.
*/
export function getTimezoneForCountry(countryCode: string | null | undefined): string {
if (!countryCode || typeof countryCode !== "string") {
return DEFAULT_TIMEZONE;
}
const normalized = countryCode.trim().toUpperCase();
if (!normalized) return DEFAULT_TIMEZONE;
return COUNTRY_TO_TIMEZONE[normalized] ?? DEFAULT_TIMEZONE;
}
/** Company columns used to resolve the effective IANA zone (no separate DB `company_timezone`). */
export interface CompanyTimezoneInput {
country?: string | null;
preferred_timezone?: string | null;
}
/**
* Resolves the effective IANA timezone for a company:
* - If preferred_timezone is set, use it.
* - Otherwise derive from country code.
* - Fallback to UTC.
*/
export function resolveCompanyTimezone(company: CompanyTimezoneInput | null | undefined): string {
if (!company) return DEFAULT_TIMEZONE;
if (company.preferred_timezone && company.preferred_timezone.trim()) {
return company.preferred_timezone.trim();
}
return getTimezoneForCountry(company.country);
}
/** Nest injectable wrapper (Company has no separate `company_timezone` column). */
@Injectable()
export class CompanyTimezoneService {
resolve(company: CompanyTimezoneInput | null | undefined): string {
return resolveCompanyTimezone(company);
}
}