Docs/Skills and code/src/
src/analysis/temporal.js
const DAY_MS = 86400000;
const PRECISE_FOR_RECENCY = new Set([
"exact_datetime", "exact_day", "estimated_minute", "estimated_hour",
"estimated_day", "estimated_week"
]);
const MONTHS = new Map([
["jan", 0], ["january", 0], ["feb", 1], ["february", 1], ["mar", 2], ["march", 2],
["apr", 3], ["april", 3], ["may", 4], ["jun", 5], ["june", 5], ["jul", 6], ["july", 6],
["aug", 7], ["august", 7], ["sep", 8], ["sept", 8], ["september", 8], ["oct", 9],
["october", 9], ["nov", 10], ["november", 10], ["dec", 11], ["december", 11]
]);
function validDate(value) {
if (!value) return null;
const date = new Date(value);
return Number.isFinite(date.getTime()) ? date : null;
}
function validUtcDay(year, month, day) {
const timestamp = Date.UTC(year, month, day);
const date = new Date(timestamp);
if (date.getUTCFullYear() !== year || date.getUTCMonth() !== month || date.getUTCDate() !== day) return null;
return date;
}
function stripDisplayPrefix(value) {
return String(value ?? "").trim().replace(/^(?:(?:first\s+)?streamed|started\s+streaming|premiered|published|uploaded|posted|originally\s+aired|aired)(?:\s+on)?\s+/i, "").trim();
}
function parseAbsoluteDisplay(value) {
const text = stripDisplayPrefix(value).replace(/^on\s+/i, "").trim();
const isoDay = text.match(/^(\d{4})-(\d{2})-(\d{2})$/);
if (isoDay) return validUtcDay(Number(isoDay[1]), Number(isoDay[2]) - 1, Number(isoDay[3]));
// Common YouTube display dates: "Sep 19, 2026", "September 19, 2026", "19 Sep 2026".
let match = text.match(/^([A-Za-z]+)\s+(\d{1,2}),?\s+(\d{4})$/);
if (match && MONTHS.has(match[1].toLowerCase())) {
return validUtcDay(Number(match[3]), MONTHS.get(match[1].toLowerCase()), Number(match[2]));
}
match = text.match(/^(\d{1,2})\s+([A-Za-z]+)\s+(\d{4})$/);
if (match && MONTHS.has(match[2].toLowerCase())) {
return validUtcDay(Number(match[3]), MONTHS.get(match[2].toLowerCase()), Number(match[1]));
}
// ISO timestamps and other explicit timestamps are accepted only when they include a time/zone.
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/.test(text)) return validDate(text);
return null;
}
function subtractCalendar(anchor, amount, unit) {
const date = new Date(anchor.getTime());
if (unit === "month" || unit === "year") {
const originalDay = date.getUTCDate();
date.setUTCDate(1);
if (unit === "year") date.setUTCFullYear(date.getUTCFullYear() - amount);
else date.setUTCMonth(date.getUTCMonth() - amount);
const lastDay = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 0)).getUTCDate();
date.setUTCDate(Math.min(originalDay, lastDay));
return date;
}
date.setTime(date.getTime() - amount * ({ minute: 60000, hour: 3600000, day: DAY_MS, week: 7 * DAY_MS }[unit] ?? DAY_MS));
return date;
}
/** Parse dates conservatively. Relative dates are estimates anchored to when the row was discovered. */
export function normalizePublishedAt(rawValue, discoveredAt) {
const raw = String(rawValue ?? "").trim();
if (!raw) return { normalized: null, precision: "unknown", method: "empty_source" };
const absolute = parseAbsoluteDisplay(raw);
if (absolute) {
const originalHasTime = /(?:T\d{2}:\d{2}|\s\d{1,2}:\d{2}(?::\d{2})?)/i.test(stripDisplayPrefix(raw));
const hadPrefix = stripDisplayPrefix(raw) !== raw;
return {
normalized: absolute.toISOString(),
precision: originalHasTime ? "exact_datetime" : "exact_day",
method: hadPrefix ? "absolute_display_value" : "absolute_source_value"
};
}
const anchor = validDate(discoveredAt);
if (!anchor) return { normalized: null, precision: "unknown", method: "relative_without_anchor" };
const lower = stripDisplayPrefix(raw).toLowerCase().replace(/\s+/g, " ");
if (/^(just now|live now)$/.test(lower)) {
return { normalized: anchor.toISOString(), precision: "estimated_minute", method: "relative_to_discovered_at" };
}
if (lower === "yesterday") {
const date = subtractCalendar(anchor, 1, "day");
return { normalized: date.toISOString(), precision: "estimated_day", method: "relative_to_discovered_at" };
}
if (lower === "today") return { normalized: anchor.toISOString(), precision: "estimated_day", method: "relative_to_discovered_at" };
const match = lower.match(/(?:published\s+)?(\d+(?:\.\d+)?)\s*(minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|wks?|w|months?|mos?|mo|years?|yrs?|yr|y)\s+ago/);
if (!match) return { normalized: null, precision: "unknown", method: "unrecognized_source_value" };
const amount = Number(match[1]);
const unitText = match[2];
let unit;
let precision;
if (/^(m|min|mins|minute|minutes)$/.test(unitText)) { unit = "minute"; precision = "estimated_minute"; }
else if (/^(h|hr|hrs|hour|hours)$/.test(unitText)) { unit = "hour"; precision = "estimated_hour"; }
else if (/^(d|day|days)$/.test(unitText)) { unit = "day"; precision = "estimated_day"; }
else if (/^(w|wk|wks|week|weeks)$/.test(unitText)) { unit = "week"; precision = "estimated_week"; }
else if (/^(mo|mos|month|months)$/.test(unitText)) { unit = "month"; precision = "estimated_month"; }
else { unit = "year"; precision = "estimated_year"; }
if (!Number.isFinite(amount) || amount < 0) return { normalized: null, precision: "unknown", method: "invalid_relative_amount" };
return { normalized: subtractCalendar(anchor, amount, unit).toISOString(), precision, method: "relative_to_discovered_at" };
}
export function isRecencyEligible(precision) {
return PRECISE_FOR_RECENCY.has(precision);
}
export function ageInDays(normalizedValue, now = new Date()) {
const date = validDate(normalizedValue);
if (!date) return null;
const age = (now.getTime() - date.getTime()) / DAY_MS;
return Number.isFinite(age) && age >= 0 ? Math.max(1, age) : null;
}
Shown as it is in the repository at build time (2026-11-03); the home directory appears as <home>. If this page and the file differ, the file is right. Back to the catalogue.