/**
* D-Sec ログのモーダルの期間(ボタンと日付の範囲)→ 一覧の `from` / `to`(指示書AY 段階3。D23)。
* 期待値の正は指示書AY §3 表2(`__tests__/presets.test.ts`)。
*
* ★純粋関数★。★実行環境のタイムゾーンに依存しない★(`toJstIso()` と `parseDate()` だけで組み立てる。表2 T10)。
*/
import { parseDate } from "@/lib/clean-logs/query";
import { toJstIso } from "@/lib/format/date";
export type DsLogPeriodPreset = "1h" | "3h" | "24h" | "all";
export interface DsLogPeriod {
/** `+09:00` の ISO。`null` = 下限なし */
from: string | null;
/** `+09:00` の ISO。`null` = 上限なし */
to: string | null;
}
const PRESET_HOURS: Record<Exclude<DsLogPeriodPreset, "all">, number> = {
"1h": 1,
"3h": 3,
"24h": 24,
};
const HOUR_MS = 60 * 60 * 1000;
const DAY_MS = 24 * HOUR_MS;
/**
* 期間ボタン(表2 T1〜T4・T10)。
* ★`to` は付けない★(D23。制御盤の時計が進んでいても最新のファイルを外さない)。
*/
export function periodFromPreset(preset: DsLogPeriodPreset, now: Date): DsLogPeriod {
if (preset === "all") return { from: null, to: null };
return { from: toJstIso(new Date(now.getTime() - PRESET_HOURS[preset] * HOUR_MS)), to: null };
}
/**
* 日付の範囲(`YYYY-MM-DD`。表2 T5〜T9)。★終了日を含む★(`to` は終了日の翌日 00:00 JST)。
* 開始 > 終了・存在しない日付は `null`(不正。画面は取得しない)。
*/
export function periodFromDates(startDate: string | null, endDate: string | null): DsLogPeriod | null {
const start = startDate ? parseDate(startDate) : null;
const end = endDate ? parseDate(endDate) : null;
if ((startDate && !start) || (endDate && !end)) return null;
if (start && end && start.getTime() > end.getTime()) return null;
return {
from: start ? toJstIso(start) : null,
to: end ? toJstIso(new Date(end.getTime() + DAY_MS)) : null,
};
}
/**
* 日付の範囲の不正の種類(指示書BJ 表D・J12)。
* ★両方とも読めて開始 > 終了なら `"reversed"`★。片方 null は範囲未確定なので `null`。
*/
export function dateRangeError(
start: string | null,
end: string | null
): "reversed" | "invalid" | null {
if (start === null || end === null) return null;
const startDate = parseDate(start);
const endDate = parseDate(end);
if (startDate === null || endDate === null) return "invalid";
if (startDate.getTime() > endDate.getTime()) return "reversed";
return null;
}