refactor: update match time utilities and improve local match window logic
- Introduced new functions `isInLocalTodayMatchWindow` and `isAfterLocalTodayMatchWindow` to enhance match time checks. - Replaced the deprecated `dayKeyInTimeZone` function with `isInLocalTodayMatchWindow` in the PlayerController. - Updated related tests and utility exports to reflect the new naming conventions. - Improved handling of local match windows in various components for better accuracy.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
export const PLATFORM_TIME_ZONE = 'Asia/Kuala_Lumpur';
|
||||
export const PLATFORM_TIME_ZONE_OFFSET_MINUTES = 8 * 60;
|
||||
export const PLATFORM_TIME_ZONE_OFFSET_LABEL = 'UTC+8';
|
||||
export const MATCH_TODAY_NEXT_DAY_CUTOFF_HOUR = 12;
|
||||
|
||||
const PICKER_DATETIME_RE =
|
||||
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2}))?$/;
|
||||
@@ -59,6 +60,63 @@ function offsetMinutesInTimeZone(date: Date, timeZone: string): number {
|
||||
return Math.round((asUtc - date.getTime()) / 60000);
|
||||
}
|
||||
|
||||
function zonedWallTimeToUtc(
|
||||
parts: { year: number; month: number; day: number; hour: number; minute?: number; second?: number },
|
||||
timeZone: string,
|
||||
): Date {
|
||||
const wallMs = Date.UTC(
|
||||
parts.year,
|
||||
parts.month - 1,
|
||||
parts.day,
|
||||
parts.hour,
|
||||
parts.minute ?? 0,
|
||||
parts.second ?? 0,
|
||||
);
|
||||
let utcMs = wallMs;
|
||||
for (let i = 0; i < 3; i += 1) {
|
||||
utcMs = wallMs - offsetMinutesInTimeZone(new Date(utcMs), timeZone) * 60 * 1000;
|
||||
}
|
||||
return new Date(utcMs);
|
||||
}
|
||||
|
||||
function localDayParts(date: Date, timeZone: string) {
|
||||
const parts = timeZoneParts(date, timeZone);
|
||||
return {
|
||||
year: Number(parts.get('year')),
|
||||
month: Number(parts.get('month')),
|
||||
day: Number(parts.get('day')),
|
||||
};
|
||||
}
|
||||
|
||||
function addDaysToParts(parts: { year: number; month: number; day: number }, days: number) {
|
||||
const d = new Date(Date.UTC(parts.year, parts.month - 1, parts.day + days));
|
||||
return {
|
||||
year: d.getUTCFullYear(),
|
||||
month: d.getUTCMonth() + 1,
|
||||
day: d.getUTCDate(),
|
||||
};
|
||||
}
|
||||
|
||||
function localTodayMatchWindow(now = new Date(), timeZone?: string) {
|
||||
if (timeZone) {
|
||||
const today = localDayParts(now, timeZone);
|
||||
const tomorrow = addDaysToParts(today, 1);
|
||||
return {
|
||||
start: zonedWallTimeToUtc({ ...today, hour: 0 }, timeZone),
|
||||
end: zonedWallTimeToUtc(
|
||||
{ ...tomorrow, hour: MATCH_TODAY_NEXT_DAY_CUTOFF_HOUR },
|
||||
timeZone,
|
||||
),
|
||||
};
|
||||
}
|
||||
const start = new Date(now);
|
||||
start.setHours(0, 0, 0, 0);
|
||||
const end = new Date(start);
|
||||
end.setDate(end.getDate() + 1);
|
||||
end.setHours(MATCH_TODAY_NEXT_DAY_CUTOFF_HOUR, 0, 0, 0);
|
||||
return { start, end };
|
||||
}
|
||||
|
||||
function parsePickerParts(value: string) {
|
||||
const match = PICKER_DATETIME_RE.exec(value.trim());
|
||||
if (!match) return null;
|
||||
@@ -190,6 +248,28 @@ export function isAfterLocalToday(value: string | Date, now = new Date(), timeZo
|
||||
return date >= end;
|
||||
}
|
||||
|
||||
export function isInLocalTodayMatchWindow(
|
||||
value: string | Date,
|
||||
now = new Date(),
|
||||
timeZone?: string,
|
||||
): boolean {
|
||||
const date = validDate(value);
|
||||
if (!date) return false;
|
||||
const { start, end } = localTodayMatchWindow(now, timeZone);
|
||||
return date >= start && date < end;
|
||||
}
|
||||
|
||||
export function isAfterLocalTodayMatchWindow(
|
||||
value: string | Date,
|
||||
now = new Date(),
|
||||
timeZone?: string,
|
||||
): boolean {
|
||||
const date = validDate(value);
|
||||
if (!date) return false;
|
||||
const { end } = localTodayMatchWindow(now, timeZone);
|
||||
return date >= end;
|
||||
}
|
||||
|
||||
export function formatLocalMatchDateTime(
|
||||
value: string | Date | null | undefined,
|
||||
locale = 'en-US',
|
||||
|
||||
Reference in New Issue
Block a user