function parseDateTimeValue(value) { if (!value || typeof value !== 'string') return null; const directDate = new Date(value); if (!Number.isNaN(directDate.getTime())) return directDate; const normalizedDate = new Date(value.replace(' ', 'T')); return Number.isNaN(normalizedDate.getTime()) ? null : normalizedDate; } function formatDateTimeForSqlite(date = new Date()) { const target = date instanceof Date ? date : new Date(date); const year = target.getFullYear(); const month = String(target.getMonth() + 1).padStart(2, '0'); const day = String(target.getDate()).padStart(2, '0'); const hours = String(target.getHours()).padStart(2, '0'); const minutes = String(target.getMinutes()).padStart(2, '0'); const seconds = String(target.getSeconds()).padStart(2, '0'); return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; } function getDateKeyFromDate(date = new Date()) { const target = date instanceof Date ? date : new Date(date); if (Number.isNaN(target.getTime())) return null; const year = target.getFullYear(); const month = String(target.getMonth() + 1).padStart(2, '0'); const day = String(target.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } function getRecentDateKeys(days = 30, now = new Date()) { const safeDays = Math.max(1, Math.floor(Number(days) || 30)); const keys = []; for (let i = safeDays - 1; i >= 0; i -= 1) { const date = new Date(now.getTime()); date.setDate(date.getDate() - i); const key = getDateKeyFromDate(date); if (key) keys.push(key); } return keys; } function getNextDownloadResetTime(lastResetAt, resetCycle) { const baseDate = parseDateTimeValue(lastResetAt); if (!baseDate) return null; const next = new Date(baseDate.getTime()); if (resetCycle === 'daily') next.setDate(next.getDate() + 1); else if (resetCycle === 'weekly') next.setDate(next.getDate() + 7); else if (resetCycle === 'monthly') next.setMonth(next.getMonth() + 1); else return null; return next; } function normalizeTimeHHmm(value) { if (typeof value !== 'string') return null; const match = value.trim().match(/^(\d{2}):(\d{2})$/); if (!match) return null; const hours = Number(match[1]); const minutes = Number(match[2]); if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59) return null; return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`; } function toMinutesOfDay(hhmm) { const normalized = normalizeTimeHHmm(hhmm); if (!normalized) return null; const [hours, minutes] = normalized.split(':').map(Number); return hours * 60 + minutes; } function isCurrentTimeInWindow(startTime, endTime, now = new Date()) { const start = toMinutesOfDay(startTime); const end = toMinutesOfDay(endTime); if (start === null || end === null) return true; const nowMinutes = now.getHours() * 60 + now.getMinutes(); if (start === end) return true; if (start < end) return nowMinutes >= start && nowMinutes < end; return nowMinutes >= start || nowMinutes < end; } module.exports = { parseDateTimeValue, formatDateTimeForSqlite, getDateKeyFromDate, getRecentDateKeys, getNextDownloadResetTime, normalizeTimeHHmm, toMinutesOfDay, isCurrentTimeInWindow };