insights-correlations (#22)
Some checks failed
CI / Check / Test (push) Has been cancelled

Reviewed-on: #22
This commit was merged in pull request #22.
This commit is contained in:
2026-10-12 18:56:55 +00:00
parent 4d221e60de
commit e303ae7f08
139 changed files with 2371 additions and 696 deletions

View File

@@ -18,18 +18,34 @@ export function shortDate(dateStr: string): string {
}
}
export function parseLocalDate(s: string): Date {
const [datePart, timePart] = s.split("T")
if (!datePart) return new Date()
const [y, m, d] = datePart.split("-").map(Number)
if (timePart) {
const [h, min, sec] = timePart.split(":").map(Number)
return new Date(y!, m! - 1, d!, h, min, sec)
}
return new Date(y!, m! - 1, d!)
// `watched_at` is stored as naive UTC ("YYYY-MM-DDTHH:MM:SS", no zone).
// Date-only imports carry no time and are stored at exactly 00:00:00; those
// are calendar dates, not instants, and must not be shifted between zones.
export function isDateOnly(s: string): boolean {
return /^\d{4}-\d{2}-\d{2}([T ]00:00(:00)?)?$/.test(s)
}
export function formatLocalDateTime(d: Date): string {
const pad = (n: number) => n.toString().padStart(2, "0")
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
export function parseWatchedAt(s: string): Date {
const [y, m, d] = s.slice(0, 10).split("-").map(Number)
if (isDateOnly(s)) return new Date(y!, m! - 1, d!)
const parsed = new Date(`${s.replace(" ", "T")}Z`)
return Number.isNaN(parsed.getTime()) ? new Date() : parsed
}
export function formatWatchedAt(d: Date, dateOnly = false): string {
const pad = (n: number) => n.toString().padStart(2, "0")
if (dateOnly) {
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T00:00:00`
}
return d.toISOString().split(".")[0]!
}
// Swap the calendar day of `current` for `picked` (the date picker yields local
// midnight), keeping the time of day so the stored UTC instant stays on the
// chosen day.
export function withPickedDay(current: Date, picked: Date): Date {
const next = new Date(current)
next.setFullYear(picked.getFullYear(), picked.getMonth(), picked.getDate())
return next
}