77 lines
2.2 KiB
TypeScript
77 lines
2.2 KiB
TypeScript
import dayjs, { type Dayjs } from "dayjs";
|
|
import customParseFormat from "dayjs/plugin/customParseFormat";
|
|
|
|
dayjs.extend(customParseFormat);
|
|
|
|
const CLOCK_DATE = "2000-01-01";
|
|
const CLOCK_TIME_FORMATS = [
|
|
"YYYY-MM-DD H:m",
|
|
"YYYY-MM-DD H:mm",
|
|
"YYYY-MM-DD HH:m",
|
|
"YYYY-MM-DD HH:mm",
|
|
];
|
|
|
|
/** Parse a timetable clock value, accepting legacy and zero-padded forms. */
|
|
export const parseClockTime = (time: string): Dayjs | null => {
|
|
const value = time?.trim();
|
|
if (!value) return null;
|
|
|
|
const parsed = dayjs(`${CLOCK_DATE} ${value}`, CLOCK_TIME_FORMATS, true);
|
|
return parsed.isValid() ? parsed : null;
|
|
};
|
|
|
|
/** Normalize a timetable clock value to HH:mm, preserving invalid input. */
|
|
export const normalizeTime = (time: string) =>
|
|
parseClockTime(time)?.format("HH:mm") ?? time;
|
|
|
|
/** Set a clock value on a base date without applying service-day rollover. */
|
|
export const setClockTime = (base: Dayjs, time: string, delayMinutes = 0) => {
|
|
const parsed = parseClockTime(time);
|
|
if (!parsed) return null;
|
|
|
|
return base
|
|
.clone()
|
|
.hour(parsed.hour())
|
|
.minute(parsed.minute())
|
|
.second(0)
|
|
.millisecond(0)
|
|
.add(delayMinutes, "minute");
|
|
};
|
|
|
|
/** Set a timetable value on a base date, treating 00:00-03:59 as service-day late night. */
|
|
export const setServiceTime = (base: Dayjs, time: string, delayMinutes = 0) => {
|
|
const parsed = parseClockTime(time);
|
|
if (!parsed) return null;
|
|
|
|
return base
|
|
.clone()
|
|
.hour(parsed.hour() < 4 ? parsed.hour() + 24 : parsed.hour())
|
|
.minute(parsed.minute())
|
|
.second(0)
|
|
.millisecond(0)
|
|
.add(delayMinutes, "minute");
|
|
};
|
|
|
|
export const getServiceTimeDifference = (
|
|
base: Dayjs,
|
|
time: string,
|
|
delayMinutes = 0
|
|
) => {
|
|
const parsed = parseClockTime(time);
|
|
const target = setServiceTime(base, time, delayMinutes);
|
|
if (!parsed || !target) return null;
|
|
|
|
const adjustedTarget =
|
|
base.hour() < 4 && parsed.hour() < 4
|
|
? target.subtract(1, "day")
|
|
: target;
|
|
return adjustedTarget.diff(base, "minute");
|
|
};
|
|
|
|
export const getServiceMinute = (time: string) => {
|
|
const parsed = parseClockTime(time);
|
|
if (!parsed) return null;
|
|
|
|
return (parsed.hour() < 4 ? parsed.hour() + 24 : parsed.hour()) * 60 + parsed.minute();
|
|
};
|