diff --git a/services/experimentAnalysis.ts b/services/experimentAnalysis.ts index a43f38c..774c575 100644 --- a/services/experimentAnalysis.ts +++ b/services/experimentAnalysis.ts @@ -264,21 +264,21 @@ export function computeDiD( salesData: CombinedKPIs[] ): DifferenceInDifferencesResult { const startDate = parseLocalDate(experiment.start_date); - const endDate = experiment.end_date ? parseLocalDate(experiment.end_date) : new Date(); + const endDate = experiment.end_date ? parseLocalDate(experiment.end_date) : new Date(new Date().setHours(0, 0, 0, 0)); - // Seasonal Baseline override logic - let beforeStart: Date; - let beforeEnd = startDate; // By default, before period goes up to the exact start date + const startTs = startDate.getTime(); + const endTs = endDate.getTime() + 86400000; // Add 24h so end bound is midnight of next day + + let beforeStartTs: number; + let beforeEndTs: number; if (experiment.baseline_start_date && experiment.baseline_end_date) { - beforeStart = parseLocalDate(experiment.baseline_start_date); - beforeEnd = parseLocalDate(experiment.baseline_end_date); - // Explicit end + 1 day so `< beforeEnd` logic includes the last day - beforeEnd = new Date(beforeEnd.getTime() + 86400000); + beforeStartTs = parseLocalDate(experiment.baseline_start_date).getTime(); + beforeEndTs = parseLocalDate(experiment.baseline_end_date).getTime() + 86400000; } else { - // Legacy auto-deduction (shifts the exact timeframe to the left) - const durationMs = endDate.getTime() - startDate.getTime(); - beforeStart = new Date(startDate.getTime() - durationMs); + const durationMs = endTs - startTs; + beforeEndTs = startTs; // Adjacent: baseline ends right at the moment experiment starts + beforeStartTs = beforeEndTs - durationMs; } const treatmentAsinSet = getExperimentAsins(experiment.asins || [], salesData); @@ -291,11 +291,6 @@ export function computeDiD( controlWeekly = aggregateWeeklyMetrics(controlAsinSet, salesData, experiment.marketplace); } - const startTs = startDate.getTime(); - const endTs = endDate.getTime(); - const beforeStartTs = beforeStart.getTime(); - const beforeEndTs = beforeEnd.getTime(); - const tSplit = splitPeriods(treatmentWeekly, startTs, endTs, beforeStartTs, beforeEndTs); const cSplit = hasControlGroup ? splitPeriods(controlWeekly, startTs, endTs, beforeStartTs, beforeEndTs) @@ -347,19 +342,21 @@ export function buildCounterfactualSeries( metric: string ): TrendDataPoint[] { const startDate = parseLocalDate(experiment.start_date); - const endDate = experiment.end_date ? parseLocalDate(experiment.end_date) : new Date(); + const endDate = experiment.end_date ? parseLocalDate(experiment.end_date) : new Date(new Date().setHours(0, 0, 0, 0)); - // Seasonal Baseline override logic - let beforeStart: Date; - let beforeEnd = startDate; + const startTs = startDate.getTime(); + const endTs = endDate.getTime() + 86400000; // Add 24h + + let beforeStartTs: number; + let beforeEndTs: number; if (experiment.baseline_start_date && experiment.baseline_end_date) { - beforeStart = parseLocalDate(experiment.baseline_start_date); - beforeEnd = parseLocalDate(experiment.baseline_end_date); - beforeEnd = new Date(beforeEnd.getTime() + 86400000); + beforeStartTs = parseLocalDate(experiment.baseline_start_date).getTime(); + beforeEndTs = parseLocalDate(experiment.baseline_end_date).getTime() + 86400000; } else { - const durationMs = endDate.getTime() - startDate.getTime(); - beforeStart = new Date(startDate.getTime() - durationMs); + const durationMs = endTs - startTs; + beforeEndTs = startTs; + beforeStartTs = beforeEndTs - durationMs; } const treatmentAsinSet = getExperimentAsins(experiment.asins || [], salesData); @@ -368,15 +365,7 @@ export function buildCounterfactualSeries( const hasControlGroup = (experiment.control_asins || []).length > 0; if (!hasControlGroup) { - // Without control group, counterfactual = flat line at pre-treatment average - const startTs = startDate.getTime(); - const endTs = endDate.getTime(); - const beforeStartTs = beforeStart.getTime(); - const beforeEndTs = beforeEnd.getTime(); - - // To calculate counterfactual, we need the "before" average. - // Treatment before period: - const { before: beforeData } = splitPeriods(treatmentWeekly, startTs, endTs, beforeStartTs, beforeEndTs); // Use splitPeriods to match exactly + const { before: beforeData } = splitPeriods(treatmentWeekly, startTs, endTs, beforeStartTs, beforeEndTs); const preAvg = avgMetric(beforeData, metric); return treatmentWeekly.map(w => ({ @@ -390,11 +379,6 @@ export function buildCounterfactualSeries( const controlAsinSet = getExperimentAsins(experiment.control_asins, salesData); const controlWeekly = aggregateWeeklyMetrics(controlAsinSet, salesData, experiment.marketplace); - const startTs = startDate.getTime(); - const endTs = endDate.getTime(); - const beforeStartTs = beforeStart.getTime(); - const beforeEndTs = beforeEnd.getTime(); - const { before: tBeforeData } = splitPeriods(treatmentWeekly, startTs, endTs, beforeStartTs, beforeEndTs); const { before: cBeforeData } = splitPeriods(controlWeekly, startTs, endTs, beforeStartTs, beforeEndTs);