fix(xtream): guard against invalid timezone strings in catchup formatter

Intl.DateTimeFormat throws RangeError for non-IANA timezone values
(e.g. 'UTC+5', offset strings) that some Xtream servers return in
server_info.timezone. Wrap the formatter in a try-catch and fall back
to client local-time formatting on failure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Eliran SapirandClaude Sonnet 4.6 committed 2026-04-30 05:58:41 -04:00
1 parent 30b8533e3a
commit c6562e6882
2 files changed
+31 -12

No files matched your search

@@ -106,5 +106,20 @@ describe('XtreamUrlService', () => {
const expected = `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}:${pad(date.getHours())}-${pad(date.getMinutes())}`;
expect(url).toContain(expected);
});
it('falls back to client local time when an invalid timezone string is given', () => {
const url = service.constructCatchupUrl(
credentials,
101,
timestamp,
timestamp + 3600,
'rest',
'UTC+5'
);
const date = new Date(timestamp * 1000);
const pad = (n: number) => String(n).padStart(2, '0');
const expected = `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}:${pad(date.getHours())}-${pad(date.getMinutes())}`;
expect(url).toContain(expected);
});
});
});
@@ -271,18 +271,22 @@ export class XtreamUrlService {
const date = new Date(timestamp * 1000);
if (timezone) {
const parts = new Intl.DateTimeFormat('en-CA', {
timeZone: timezone,
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
hour12: false,
}).formatToParts(date);
const get = (type: Intl.DateTimeFormatPartTypes) =>
parts.find((p) => p.type === type)?.value ?? '00';
return `${get('year')}-${get('month')}-${get('day')}:${get('hour')}-${get('minute')}`;
try {
const parts = new Intl.DateTimeFormat('en-CA', {
timeZone: timezone,
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
hour12: false,
}).formatToParts(date);
const get = (type: Intl.DateTimeFormatPartTypes) =>
parts.find((p) => p.type === type)?.value ?? '00';
return `${get('year')}-${get('month')}-${get('day')}:${get('hour')}-${get('minute')}`;
} catch {
// Invalid timezone string — fall through to local-time formatting
}
}
const pad = (value: number) => String(value).padStart(2, '0');