/** * 客户月度接口固定返回“截至查询结束日的近 12 个月”。 * 键保留完整 YYYY-MM,避免跨年时把不同年份的同月合并。 */ export function customerMonthRange(asOfYmd: string, count = 12): string[] { const matched = /^(\d{4})-(\d{2})-\d{2}$/.exec(asOfYmd); if (!matched || count < 1) return []; const endYear = Number(matched[1]); const endMonth = Number(matched[2]); if (endMonth < 1 || endMonth > 12) return []; const months: string[] = []; for (let offset = count - 1; offset >= 0; offset -= 1) { const date = new Date(Date.UTC(endYear, endMonth - 1 - offset, 1)); months.push(`${date.getUTCFullYear()}-${String(date.getUTCMonth() + 1).padStart(2, '0')}`); } return months; } export function customerMonthLabel(monthKey: string): string { const matched = /^(\d{4})-(\d{2})$/.exec(monthKey); return matched ? `${matched[1]}年${Number(matched[2])}月` : monthKey; } /** 闭区间日数;用于让卡片副标题与实际查询口径保持一致。 */ export function inclusiveDayCount(start: string, end: string): number { const startTime = Date.parse(`${start}T00:00:00Z`); const endTime = Date.parse(`${end}T00:00:00Z`); if (!Number.isFinite(startTime) || !Number.isFinite(endTime) || endTime < startTime) return 0; return Math.floor((endTime - startTime) / 86_400_000) + 1; } export function dateRangeLabel(start: string, end: string): string { const days = inclusiveDayCount(start, end); return days > 0 ? `${start} 至 ${end}(共 ${days} 天)` : `${start} 至 ${end}`; }