import moment from 'moment' import { type CompareWith, type TimeframeType, } from '../components/HeaderMetric/HeaderMetricHelpers' const isCurrentQuarterComparison = (timeframe?: TimeframeType) => timeframe && timeframe.type === 'quarterly' && moment().quarter() === timeframe?.quarter && moment().year().toString() === timeframe?.year?.toString() const isCurrentYearComparison = (timeframe?: TimeframeType) => timeframe && timeframe.type === 'quarterly' && !timeframe.quarter && moment().year().toString() === timeframe?.year?.toString() // This logic makes sure that timeframes with the potential to have the // current date in the range (current, quarterly, yearly) don't have to // handle an end date that is in the future export const isCurrentDateUsedForComparison = ( timeframe?: TimeframeType, compareWith?: CompareWith, ) => compareWith && (timeframe?.type === 'current' || isCurrentQuarterComparison(timeframe) || isCurrentYearComparison(timeframe)) type ComparisonDatesType = { startDate: string endDate: string timeframe: TimeframeType & { compareDisplay?: string } compareWith?: CompareWith hasNoCurrentMonthData?: boolean } export const getComparisonDates = ({ startDate, endDate, timeframe, compareWith, hasNoCurrentMonthData, }: ComparisonDatesType) => { const formatDates = (start: moment.Moment, end: moment.Moment) => ({ startDate: start.format(), endDate: end.format(), }) if ( isCurrentDateUsedForComparison(timeframe, compareWith) && !hasNoCurrentMonthData ) { endDate = moment().endOf('day').format() } // Handles previous year and previous month comparisons const start = moment(startDate) const end = moment(endDate) // Check for full-month and full-year selections const isFullMonth = start.date() === 1 && end.isSame(start.clone().endOf('month'), 'day') const isFullYear = start.date() === 1 && start.month() === 0 && end.isSame(start.clone().endOf('year'), 'day') // Apply full-period logic only if it's NOT a custom timeframe with compareDisplay enabled const isAllowedToCompare = !( timeframe?.value === 'custom' && timeframe?.compareDisplay ) if (isAllowedToCompare) { if (compareWith === 'previous_year' && isFullYear) { const previousYearStart = start .clone() .subtract(1, 'year') .startOf('year') const previousYearEnd = start.clone().subtract(1, 'year').endOf('year') return formatDates(previousYearStart, previousYearEnd) } if (compareWith === 'previous_period' && (isFullMonth || isFullYear)) { if (isFullYear) { const previousYearStart = start .clone() .subtract(1, 'year') .startOf('year') const previousYearEnd = start.clone().subtract(1, 'year').endOf('year') return formatDates(previousYearStart, previousYearEnd) } if (isFullMonth) { const previousMonthStart = start .clone() .subtract(1, 'month') .startOf('month') const previousMonthEnd = start .clone() .subtract(1, 'month') .endOf('month') return formatDates(previousMonthStart, previousMonthEnd) } } } // Handles previous year comparisons for all timeframes except custom timeframes with explicitly set comparison dates if ( compareWith === 'previous_year' && !(timeframe.value === 'custom' && timeframe?.compareDisplay) // handled later, we don't care about compareWith in this case ) { const start = moment(startDate) const end = moment(endDate) start.subtract(1, 'year') end.subtract(1, 'year') return formatDates(start, end) } // Previous period comparisons switch (timeframe.type) { case 'current': return { startDate: moment(startDate).subtract(1, timeframe.timeValue).format(), endDate: moment(endDate).subtract(1, timeframe.timeValue).format(), } case 'previous': return { startDate: moment(startDate) .subtract(1, timeframe.timeValue) .startOf(timeframe.timeValue) .format(), endDate: moment(endDate) .subtract(1, timeframe.timeValue) .endOf(timeframe.timeValue) .format(), } case 'historical': case 'trailing': if (timeframe?.value === 'custom') { // The user has selected custom comparison dates. We don't care about compareWith in this case. if (timeframe?.compareDisplay) { const [start, end] = timeframe.compareDisplay.split(' - ') return formatDates(moment(start), moment(end)) } // The user has selected a custom timeframe but not custom comparison dates else { const diff = moment(endDate).diff(moment(startDate), 'day') + 1 return { startDate: moment(startDate).subtract(diff, 'days').format(), endDate: moment(startDate) .subtract(1, 'days') .endOf('day') .format(), } } } return { startDate: moment(startDate) .subtract(timeframe.value, timeframe.timeValue) .format(), endDate: timeframe.timeValue === 'hours' ? moment(startDate).format() : moment(startDate).subtract(1, 'days').format(), } // Handles quarter and year comparisons case 'quarterly': // The user has selected a quarter comparison if (timeframe.quarter && !timeframe.year) { const selectedYear = moment(timeframe.year, 'YYYY') const previousQuarter = (timeframe.quarter || 1) - 1 const start = selectedYear .clone() .quarter(previousQuarter) .startOf('quarter') let end = selectedYear.clone().quarter(previousQuarter).endOf('quarter') // If the current date's quarter is the selected quarter, comparison should only reflect the amount of time passed in the current quarter if (isCurrentQuarterComparison(timeframe)) { end = moment().quarter(previousQuarter).endOf('day') if (hasNoCurrentMonthData) { end = moment(endDate).subtract(1, 'quarters').endOf('month') } } return formatDates(start, end) } // The user has selected a year comparison else { const start = moment(startDate).subtract(1, timeframe.timeValue) let end = moment(endDate).subtract(1, timeframe.timeValue) // If the current date's year is the selected year, comparison should only reflect the amount of time passed in the current year if (isCurrentYearComparison(timeframe)) { end = moment().subtract(1, timeframe.timeValue).endOf('day') if (hasNoCurrentMonthData) { end = moment().subtract(1, 'months').endOf('month') } } return formatDates(moment(start), moment(end)) } default: break } }