forked from Yara724/api
Fixed timing issue with UTC
This commit is contained in:
82
src/helpers/iran-datetime.ts
Normal file
82
src/helpers/iran-datetime.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
/** Iran standard time (Asia/Tehran, UTC+3:30; no DST since 2022). */
|
||||
export const IRAN_TIMEZONE = "Asia/Tehran";
|
||||
|
||||
const IRAN_UTC_OFFSET = "+03:30";
|
||||
|
||||
const DATE_ONLY_RE = /^\d{4}-\d{2}-\d{2}$/;
|
||||
const TIME_HM_RE = /^(\d{1,2}):(\d{2})(?::(\d{2}))?$/;
|
||||
const NAIVE_ISO_DATETIME_RE =
|
||||
/^(\d{4}-\d{2}-\d{2})[T\s](\d{1,2}:\d{2}(?::\d{2})?)$/;
|
||||
|
||||
/**
|
||||
* Gregorian calendar date (`YYYY-MM-DD`) for an instant in Iran.
|
||||
*/
|
||||
export function gregorianDateInIran(d: Date): string {
|
||||
return new Intl.DateTimeFormat("en-CA", {
|
||||
timeZone: IRAN_TIMEZONE,
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
}).format(d);
|
||||
}
|
||||
|
||||
function normalizeTimeToHms(time: string): string | null {
|
||||
const m = String(time).trim().match(TIME_HM_RE);
|
||||
if (!m) return null;
|
||||
const hh = m[1].padStart(2, "0");
|
||||
const mm = m[2];
|
||||
const ss = m[3] ?? "00";
|
||||
return `${hh}:${mm}:${ss}`;
|
||||
}
|
||||
|
||||
function parseIranLocalIso(isoDate: string, timeHms: string): Date | null {
|
||||
const d = new Date(`${isoDate}T${timeHms}${IRAN_UTC_OFFSET}`);
|
||||
return Number.isNaN(d.getTime()) ? null : d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines a calendar date and optional `HH:MM` / `HH:MM:SS` as Iran local
|
||||
* time and returns the corresponding UTC instant.
|
||||
*/
|
||||
export function parseIranLocalDateTime(
|
||||
date: Date | string,
|
||||
time?: string,
|
||||
): Date | null {
|
||||
if (date instanceof Date) {
|
||||
if (Number.isNaN(date.getTime())) return null;
|
||||
const cleanTime = (time ?? "").trim();
|
||||
if (!cleanTime) return date;
|
||||
const timeHms = normalizeTimeToHms(cleanTime);
|
||||
if (!timeHms) return null;
|
||||
return parseIranLocalIso(gregorianDateInIran(date), timeHms);
|
||||
}
|
||||
|
||||
const raw = String(date).trim();
|
||||
if (!raw) return null;
|
||||
|
||||
if (/[zZ]|[+-]\d{2}:?\d{2}$/.test(raw)) {
|
||||
const d = new Date(raw);
|
||||
return Number.isNaN(d.getTime()) ? null : d;
|
||||
}
|
||||
|
||||
const naive = raw.match(NAIVE_ISO_DATETIME_RE);
|
||||
if (naive) {
|
||||
const timeHms = normalizeTimeToHms(naive[2]);
|
||||
if (!timeHms) return null;
|
||||
return parseIranLocalIso(naive[1], timeHms);
|
||||
}
|
||||
|
||||
if (DATE_ONLY_RE.test(raw)) {
|
||||
const cleanTime = (time ?? "").trim();
|
||||
if (!cleanTime) {
|
||||
const d = new Date(`${raw}T00:00:00${IRAN_UTC_OFFSET}`);
|
||||
return Number.isNaN(d.getTime()) ? null : d;
|
||||
}
|
||||
const timeHms = normalizeTimeToHms(cleanTime);
|
||||
if (!timeHms) return null;
|
||||
return parseIranLocalIso(raw, timeHms);
|
||||
}
|
||||
|
||||
const d = new Date(raw);
|
||||
return Number.isNaN(d.getTime()) ? null : d;
|
||||
}
|
||||
Reference in New Issue
Block a user