// Time utilities for handling business day logic and time ranges // Business day is 1am-12:59am Eastern time (UTC-5) const getBusinessDayBounds = (timeRange) => { const now = new Date(); const easternTime = new Date(now.getTime() - (5 * 60 * 60 * 1000)); // UTC-5 switch (timeRange) { case 'today': { const start = new Date(easternTime); start.setHours(1, 0, 0, 0); // 1 AM start of business day const end = new Date(start); end.setDate(end.getDate() + 1); end.setHours(0, 59, 59, 999); // 12:59 AM next day return { start, end }; } case 'yesterday': { const start = new Date(easternTime); start.setDate(start.getDate() - 1); start.setHours(1, 0, 0, 0); const end = new Date(start); end.setDate(end.getDate() + 1); end.setHours(0, 59, 59, 999); return { start, end }; } case 'thisWeek': { const start = new Date(easternTime); start.setDate(easternTime.getDate() - easternTime.getDay()); // Sunday start.setHours(1, 0, 0, 0); const end = new Date(easternTime); end.setDate(end.getDate() + 1); end.setHours(0, 59, 59, 999); return { start, end }; } case 'lastWeek': { const start = new Date(easternTime); start.setDate(easternTime.getDate() - easternTime.getDay() - 7); // Previous Sunday start.setHours(1, 0, 0, 0); const end = new Date(start); end.setDate(end.getDate() + 7); end.setHours(0, 59, 59, 999); return { start, end }; } case 'thisMonth': { const start = new Date(easternTime.getFullYear(), easternTime.getMonth(), 1, 1, 0, 0, 0); const end = new Date(easternTime); end.setDate(end.getDate() + 1); end.setHours(0, 59, 59, 999); return { start, end }; } case 'lastMonth': { const start = new Date(easternTime.getFullYear(), easternTime.getMonth() - 1, 1, 1, 0, 0, 0); const end = new Date(easternTime.getFullYear(), easternTime.getMonth(), 1, 0, 59, 59, 999); return { start, end }; } case 'last7days': { const end = new Date(easternTime); end.setHours(0, 59, 59, 999); const start = new Date(end); start.setDate(start.getDate() - 7); start.setHours(1, 0, 0, 0); return { start, end }; } case 'last30days': { const end = new Date(easternTime); end.setHours(0, 59, 59, 999); const start = new Date(end); start.setDate(start.getDate() - 30); start.setHours(1, 0, 0, 0); return { start, end }; } case 'last90days': { const end = new Date(easternTime); end.setHours(0, 59, 59, 999); const start = new Date(end); start.setDate(start.getDate() - 90); start.setHours(1, 0, 0, 0); return { start, end }; } case 'previous7days': { const end = new Date(easternTime); end.setDate(end.getDate() - 1); end.setHours(0, 59, 59, 999); const start = new Date(end); start.setDate(start.getDate() - 6); start.setHours(1, 0, 0, 0); return { start, end }; } case 'previous30days': { const end = new Date(easternTime); end.setDate(end.getDate() - 1); end.setHours(0, 59, 59, 999); const start = new Date(end); start.setDate(start.getDate() - 29); start.setHours(1, 0, 0, 0); return { start, end }; } case 'previous90days': { const end = new Date(easternTime); end.setDate(end.getDate() - 1); end.setHours(0, 59, 59, 999); const start = new Date(end); start.setDate(start.getDate() - 89); start.setHours(1, 0, 0, 0); return { start, end }; } case 'twoDaysAgo': { const start = new Date(easternTime); start.setDate(start.getDate() - 2); start.setHours(1, 0, 0, 0); const end = new Date(start); end.setDate(end.getDate() + 1); end.setHours(0, 59, 59, 999); return { start, end }; } default: throw new Error(`Unknown time range: ${timeRange}`); } }; const getTimeRangeConditions = (timeRange, startDate, endDate) => { if (timeRange === 'custom' && startDate && endDate) { // Custom date range const start = new Date(startDate); const end = new Date(endDate); // Convert to UTC-5 (Eastern time) const startUTC5 = new Date(start.getTime() - (5 * 60 * 60 * 1000)); const endUTC5 = new Date(end.getTime() - (5 * 60 * 60 * 1000)); return { whereClause: 'date_placed >= ? AND date_placed <= ?', params: [ startUTC5.toISOString().slice(0, 19).replace('T', ' '), endUTC5.toISOString().slice(0, 19).replace('T', ' ') ], dateRange: { start: startDate, end: endDate, label: `${formatBusinessDate(start)} - ${formatBusinessDate(end)}` } }; } if (!timeRange) { timeRange = 'today'; } const { start, end } = getBusinessDayBounds(timeRange); // Convert to MySQL datetime format (UTC-5) const startStr = start.toISOString().slice(0, 19).replace('T', ' '); const endStr = end.toISOString().slice(0, 19).replace('T', ' '); return { whereClause: 'date_placed >= ? AND date_placed <= ?', params: [startStr, endStr], dateRange: { start: start.toISOString(), end: end.toISOString(), label: getTimeRangeLabel(timeRange) } }; }; const formatBusinessDate = (date) => { return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }); }; const getTimeRangeLabel = (timeRange) => { const labels = { today: 'Today', yesterday: 'Yesterday', thisWeek: 'This Week', lastWeek: 'Last Week', thisMonth: 'This Month', lastMonth: 'Last Month', last7days: 'Last 7 Days', last30days: 'Last 30 Days', last90days: 'Last 90 Days', previous7days: 'Previous 7 Days', previous30days: 'Previous 30 Days', previous90days: 'Previous 90 Days', twoDaysAgo: 'Two Days Ago' }; return labels[timeRange] || timeRange; }; // Helper to convert MySQL datetime to JavaScript Date const parseBusinessDate = (mysqlDatetime) => { if (!mysqlDatetime || mysqlDatetime === '0000-00-00 00:00:00') { return null; } // MySQL datetime is stored in UTC-5, so we need to add 5 hours to get UTC const date = new Date(mysqlDatetime + ' UTC'); date.setHours(date.getHours() + 5); return date; }; // Helper to format date for MySQL queries const formatMySQLDate = (date) => { if (!date) return null; // Convert to UTC-5 for storage const utc5Date = new Date(date.getTime() - (5 * 60 * 60 * 1000)); return utc5Date.toISOString().slice(0, 19).replace('T', ' '); }; module.exports = { getBusinessDayBounds, getTimeRangeConditions, formatBusinessDate, getTimeRangeLabel, parseBusinessDate, formatMySQLDate };