/**
* 秒数を「○分○秒」形式に変換
*/
export function formatDuration(seconds: number): string {
if (isNaN(seconds) || seconds < 0) {
return "0秒";
}
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const secs = Math.floor(seconds % 60);
const parts: string[] = [];
if (hours > 0) {
parts.push(`${hours}時間`);
}
if (minutes > 0) {
parts.push(`${minutes}分`);
}
if (secs > 0 || parts.length === 0) {
parts.push(`${secs}秒`);
}
return parts.join("");
}
/**
* 数値をカンマ区切りにフォーマット
*/
export function formatNumber(num: number): string {
if (isNaN(num)) {
return "0";
}
return num.toLocaleString("ja-JP");
}
/**
* 小数点以下を指定桁数で丸める
*/
export function roundToDecimal(num: number, decimals: number = 2): number {
if (isNaN(num)) {
return 0;
}
const factor = Math.pow(10, decimals);
return Math.round(num * factor) / factor;
}
/**
* GA4のメトリクス名を人間が読みやすい形式に変換
*/
export function formatMetricName(metricName: string): string {
const metricLabels: Record<string, string> = {
screenPageViews: "ページビュー",
activeUsers: "アクティブユーザー",
newUsers: "新規ユーザー",
totalUsers: "総ユーザー",
sessions: "セッション",
engagementRate: "エンゲージメント率",
averageSessionDuration: "平均セッション時間",
bounceRate: "直帰率",
sessionsPerUser: "ユーザーあたりセッション",
screenPageViewsPerSession: "セッションあたりPV",
eventCount: "イベント数",
conversions: "コンバージョン",
userEngagementDuration: "エンゲージメント時間",
engagedSessions: "エンゲージセッション",
entrances: "入口数",
exits: "離脱数",
eventCountPerUser: "ユーザーあたりイベント",
};
return metricLabels[metricName] || metricName;
}
/**
* GA4のディメンション名を人間が読みやすい形式に変換
*/
export function formatDimensionName(dimensionName: string): string {
const dimensionLabels: Record<string, string> = {
pagePath: "ページパス",
pageTitle: "ページタイトル",
deviceCategory: "デバイスカテゴリ",
country: "国",
city: "市区町村",
browser: "ブラウザ",
operatingSystem: "OS",
sessionSource: "セッションソース",
sessionMedium: "セッションメディア",
sessionCampaignName: "キャンペーン名",
sessionDefaultChannelGroup: "デフォルトチャネル",
date: "日付",
hour: "時間",
newVsReturning: "新規/リピーター",
landingPage: "ランディングページ",
exitPage: "離脱ページ",
};
return dimensionLabels[dimensionName] || dimensionName;
}
/**
* 変化量を文字列形式で表現
*/
export function formatChange(current: number, previous: number): { change: number; changePercent: string; trend: "up" | "down" | "flat" } {
const change = current - previous;
if (previous === 0) {
if (current === 0) {
return { change: 0, changePercent: "0%", trend: "flat" };
}
return { change, changePercent: "+∞%", trend: "up" };
}
const changePercent = (change / previous) * 100;
const sign = changePercent >= 0 ? "+" : "";
const trend = changePercent > 0.5 ? "up" : changePercent < -0.5 ? "down" : "flat";
return {
change: roundToDecimal(change),
changePercent: `${sign}${roundToDecimal(changePercent)}%`,
trend,
};
}