import type { Period, DateRange } from "../types.js";
/**
* 相対日付文字列を YYYY-MM-DD 形式に変換
*/
export function resolveDate(dateStr: string): string {
// すでに YYYY-MM-DD 形式ならそのまま返す
if (/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) {
return dateStr;
}
const today = new Date();
today.setHours(0, 0, 0, 0);
switch (dateStr.toLowerCase()) {
case "today":
return formatDate(today);
case "yesterday":
const yesterday = new Date(today);
yesterday.setDate(yesterday.getDate() - 1);
return formatDate(yesterday);
default:
// NdaysAgo 形式をパース
const match = dateStr.match(/^(\d+)daysAgo$/i);
if (match) {
const daysAgo = parseInt(match[1], 10);
const date = new Date(today);
date.setDate(date.getDate() - daysAgo);
return formatDate(date);
}
throw new Error(`Invalid date format: ${dateStr}`);
}
}
/**
* Date を YYYY-MM-DD 形式に変換
*/
export function formatDate(date: Date): string {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
return `${year}-${month}-${day}`;
}
/**
* Period を DateRange に変換
*/
export function periodToDateRange(period: Period): DateRange {
const today = new Date();
today.setHours(0, 0, 0, 0);
const endDate = formatDate(today);
let startDate: string;
switch (period) {
case "today":
startDate = endDate;
break;
case "yesterday":
const yesterday = new Date(today);
yesterday.setDate(yesterday.getDate() - 1);
startDate = formatDate(yesterday);
break;
case "7days":
const sevenDaysAgo = new Date(today);
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 6);
startDate = formatDate(sevenDaysAgo);
break;
case "28days":
const twentyEightDaysAgo = new Date(today);
twentyEightDaysAgo.setDate(twentyEightDaysAgo.getDate() - 27);
startDate = formatDate(twentyEightDaysAgo);
break;
case "30days":
const thirtyDaysAgo = new Date(today);
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 29);
startDate = formatDate(thirtyDaysAgo);
break;
case "90days":
const ninetyDaysAgo = new Date(today);
ninetyDaysAgo.setDate(ninetyDaysAgo.getDate() - 89);
startDate = formatDate(ninetyDaysAgo);
break;
}
return { startDate, endDate };
}
/**
* 前の期間を計算(同じ日数分前にずらす)
*/
export function getPreviousPeriod(dateRange: DateRange): DateRange {
const start = new Date(dateRange.startDate);
const end = new Date(dateRange.endDate);
const daysDiff = Math.ceil((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)) + 1;
const prevEnd = new Date(start);
prevEnd.setDate(prevEnd.getDate() - 1);
const prevStart = new Date(prevEnd);
prevStart.setDate(prevStart.getDate() - daysDiff + 1);
return {
startDate: formatDate(prevStart),
endDate: formatDate(prevEnd),
};
}
/**
* 前年同期を計算
*/
export function getPreviousYearPeriod(dateRange: DateRange): DateRange {
const start = new Date(dateRange.startDate);
const end = new Date(dateRange.endDate);
start.setFullYear(start.getFullYear() - 1);
end.setFullYear(end.getFullYear() - 1);
return {
startDate: formatDate(start),
endDate: formatDate(end),
};
}
/**
* 日付範囲の日数を取得
*/
export function getDayCount(dateRange: DateRange): number {
const start = new Date(dateRange.startDate);
const end = new Date(dateRange.endDate);
return Math.ceil((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)) + 1;
}
/**
* 期間のラベルを生成
*/
export function getPeriodLabel(dateRange: DateRange): string {
const dayCount = getDayCount(dateRange);
return `${dateRange.startDate} 〜 ${dateRange.endDate} (${dayCount}日間)`;
}