@tmlmobilidade/types
Version:
91 lines (90 loc) • 2.71 kB
JavaScript
/* * */
import { z } from 'zod';
/* * */
const OPERATIONAL_DAY_START_HOUR = 4;
const OPERATIONAL_DAY_END_HOUR = 29;
/**
* Parses an operational HH:MM.
*
* Rules:
* - minimum is 04:00
* - maximum is 29:59
* - minutes must be 00–59
* - hour must be at least 2 digits in stored format
*/
export function operationalHhmmToMinutes(hhmm, ignoreStartHour = false) {
const match = /^(\d{2,}):(\d{2})$/.exec(hhmm);
if (!match) {
throw new Error(`Invalid operational time: ${hhmm}`);
}
const hours = Number(match[1]);
const minutes = Number(match[2]);
if (Number.isNaN(hours) || Number.isNaN(minutes)) {
throw new Error(`Invalid operational time: ${hhmm}`);
}
if (minutes < 0 || minutes > 59) {
throw new Error(`Invalid minutes in operational time: ${hhmm}`);
}
const total = hours * 60 + minutes;
const minAllowed = OPERATIONAL_DAY_START_HOUR * 60; // 04:00
if (!ignoreStartHour && total < minAllowed) {
throw new Error(`Operational time out of range: ${hhmm}`);
}
const maxAllowed = (OPERATIONAL_DAY_END_HOUR * 60) + 59; // 29:59
if (!ignoreStartHour && total > maxAllowed) {
throw new Error(`Operational time out of range: ${hhmm}`);
}
return total;
}
/**
* Converts common typed time formats into strict HH:MM.
*
* Examples:
* - "800" -> "08:00"
* - "0800" -> "08:00"
* - "2200" -> "22:00"
* - "2600" -> "26:00"
* - "8:00" -> "08:00"
* - "26:00" -> "26:00"
*
* Returns null if it cannot normalize safely.
*/
export function normalizeOperationalHhmmInput(value) {
const trimmed = value.trim();
if (!trimmed)
return null;
// Pure digits: last 2 are minutes, everything before is hours
if (/^\d{3,}$/.test(trimmed)) {
const hours = trimmed.slice(0, -2);
const minutes = trimmed.slice(-2);
return `${hours.padStart(2, '0')}:${minutes}`;
}
// HH:MM with any hour length >= 1
const match = /^(\d+):(\d{2})$/.exec(trimmed);
if (match) {
const [, hours, minutes] = match;
return `${hours.padStart(2, '0')}:${minutes}`;
}
return null;
}
export const HHMMSchema = z
.string()
.refine((value) => {
try {
operationalHhmmToMinutes(value);
return true;
}
catch (err) {
console.warn('Invalid HHMM:', value, err);
return false;
}
}, 'Invalid operational time (expected HH:MM between 04:00 and 29:59)')
.brand();
/**
* Runtime-safe creator (validates + brands)
*/
export const hhmm = (value) => HHMMSchema.parse(value);
/* * */
export function timeToMinutes(time, ignoreStartHour = false) {
return operationalHhmmToMinutes(time, ignoreStartHour);
}