import { getCompanyInfo } from "../services/mm-api-service/company-info.js"; import { getIANATimezoneOffsetHours } from "./iana-timezone-offset.js"; /** * Gets the timezone offset in hours and timezone name for the company's timezone * (uses cached {@link getCompanyInfo} — no extra HTTP when already loaded). * @returns Promise<{ offset: number; timezone: string }> The timezone offset in hours and timezone name * @throws Error if unable to fetch timezone information */ export const getTimezoneOffset = async (): Promise<{ offset: number; timezone: string }> => { try { const info = await getCompanyInfo(); const offset = getIANATimezoneOffsetHours(info.timezone); return { offset, timezone: info.timezone }; } catch (error) { throw new Error( `Failed to get timezone offset: ${error instanceof Error ? error.message : "Unknown error"}` ); } }; /** * Converts a UTC/Zulu time to local time based on the provided timezone offset * @param zuluTime The UTC/Zulu time to convert * @param timezoneOffset The timezone offset in hours * @returns The converted local time, or undefined if input is null/undefined */ export const convertToLocalTime = ( zuluTime: string | Date | null | undefined, timezoneOffset: number ): Date | undefined => { if (!zuluTime) return undefined; const date = new Date(zuluTime); return new Date(date.getTime() + timezoneOffset * 60 * 60 * 1000); }; /** * Formats a date with the timezone offset in ISO format with offset * @param date The date string in format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss * @param timezoneOffset The timezone offset in hours * @returns The formatted date string in format: YYYY-MM-DDTHH:mm:ss+/-HH:MM */ export const formatDateWithTZOffset = ( date: string | null | undefined, timezoneOffset: number ): string | undefined => { if (!date) return undefined; // Replace space with T if present const isoDate = date.replace(" ", "T"); // Calculate offset components const sign = timezoneOffset >= 0 ? "+" : "-"; const absOffset = Math.abs(timezoneOffset); const hours = Math.floor(absOffset).toString().padStart(2, "0"); const minutes = Math.floor((absOffset % 1) * 60) .toString() .padStart(2, "0"); // Append the timezone offset return `${isoDate}${sign}${hours}:${minutes}`; }; /** * Formats a Date object as an ISO string with the specified timezone offset * @param date The Date object to format (should be a Date that has been shifted by convertToLocalTime) * @param timezoneOffset The timezone offset in hours * @returns ISO string with offset in format: YYYY-MM-DDTHH:mm:ss.SSS±HH:MM */ export const toISOWithOffset = (date: Date, timezoneOffset: number): string => { const sign = timezoneOffset >= 0 ? "+" : "-"; const abs = Math.abs(timezoneOffset); const hours = Math.floor(abs); const minutes = Math.round((abs - hours) * 60); const pad2 = (n: number) => n.toString().padStart(2, "0"); const pad3 = (n: number) => n.toString().padStart(3, "0"); // Use UTC getters since convertToLocalTime shifts the Date's internal timestamp // The UTC components of the shifted Date represent the local wall time const yyyy = date.getUTCFullYear(); const MM = pad2(date.getUTCMonth() + 1); const dd = pad2(date.getUTCDate()); const HH = pad2(date.getUTCHours()); const mm = pad2(date.getUTCMinutes()); const ss = pad2(date.getUTCSeconds()); const SSS = pad3(date.getUTCMilliseconds()); const off = `${sign}${pad2(hours)}:${pad2(minutes)}`; return `${yyyy}-${MM}-${dd}T${HH}:${mm}:${ss}.${SSS}${off}`; };