feat: complete AI analytics experience

This commit is contained in:
2026-08-22 15:47:26 +08:00
parent 2bea50a291
commit 43f65a8259
35 changed files with 3497 additions and 574 deletions

View File

@@ -0,0 +1,34 @@
const tehranParts = new Intl.DateTimeFormat('en-CA', {
timeZone: 'Asia/Tehran',
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hourCycle: 'h23',
});
function parts(value: Date) {
return Object.fromEntries(
tehranParts
.formatToParts(value)
.filter((part) => part.type !== 'literal')
.map((part) => [part.type, Number(part.value)]),
);
}
function tehranOffset(value: Date) {
const local = parts(value);
return (
Date.UTC(local.year, local.month - 1, local.day, local.hour, local.minute, local.second) - value.getTime()
);
}
export function millisecondsUntilTehranMidnight(now = new Date()): number {
const local = parts(now);
const targetAsUTC = Date.UTC(local.year, local.month - 1, local.day + 1);
let target = new Date(targetAsUTC - tehranOffset(now));
target = new Date(targetAsUTC - tehranOffset(target));
return Math.max(0, target.getTime() - now.getTime());
}