export interface Tidspunkt { minutter: number; timer: number; } export interface Periode { fra: Tidspunkt; til: Tidspunkt; } export const timerGyldig = (timer: number): boolean => timer >= 0 && timer < 24; export const minutterGyldig = (minutter: number): boolean => minutter >= 0 && minutter < 60; export const tidspunktGyldig = (timer: number, minutter: number): boolean => timerGyldig(timer) && minutterGyldig(minutter); export function timerOgMinutterTilTidspunkt( timer: number, minutter: number ): Tidspunkt { return { timer, minutter }; } export function intervallKrysserMidnatt({ fra, til }: Periode): boolean { return compareTidspunkt(fra, til) > 0; } export function erPeriodeInnenforEnAvPeriodene( periode: Periode, perioder: Periode[] ): boolean { return perioder.some( (p: Periode) => compareTidspunkt(periode.fra, p.fra) >= 0 && compareTidspunkt(periode.til, p.til) <= 0 ); } export function comparePeriode( { fra: fraA, til: tilA }: Periode, { fra: fraB, til: tilB }: Periode ): number { const startForskjell = compareTidspunkt(fraA, fraB); if (startForskjell === 0) { return compareTidspunkt(tilA, tilB); } return startForskjell; } export function isPeriode(periode: Periode | undefined): periode is Periode { return periode !== undefined && periode !== null; } export function compareTidspunkt( { timer: timerA, minutter: minutterA }: Tidspunkt, { timer: timerB, minutter: minutterB }: Tidspunkt ): number { const timeForskjell = timerA - timerB; if (timeForskjell === 0) { return minutterA - minutterB; } return timeForskjell; } export function periodeTilTekst({ fra, til }: Periode): string { function padMedNull(streng) { return `0${streng}`.slice(-2); // de to siste tegnene } // språkrådet-approved formatering av klokkeslett som periode // https://www.sprakradet.no/sprakhjelp/Skriveregler/Dato/ return `kl. ${padMedNull(fra.timer)}:${padMedNull( fra.minutter )}–${padMedNull(til.timer)}:${padMedNull(til.minutter)}`; } export function overlapperIntervall( intervallA: Periode, intervallB: Periode ): boolean { const [starterForst, starterSist] = [intervallA, intervallB].sort( comparePeriode ); if (intervallKrysserMidnatt(starterForst)) { // ja, de må overlappe siden intervallet som starter tidligst i dagene går over midnatt // intervall 1 [--------00:00---------] // intervall 2 [-- her har ikke slutten av intervall 2 noe å si return true; } // Hvis de slutter og starter i et overlappende tidspunkt sier vi at de overlapper if (compareTidspunkt(starterForst.til, starterSist.fra) === 0) { return true; } if (intervallKrysserMidnatt(starterSist)) { // Hvis intervall 2 går over midnatt kan de overlappe i delen av intervallet før midnatt, // eller i delen av intervallet etter midnatt // // før midnatt: // intervall 1: [----------] // intervall 2: [------00:00--------] // her er intervall1 sin slutt _etter_ intervall2 sin start // // etter midnatt: // intervall 1: [----------] // intervall 2: [------00:00--------] // her er intervall 1 sin start _før_ intervall2 sin slutt const overlapperFoerMidnatt = compareTidspunkt(starterForst.til, starterSist.fra) > 0; const overlapperEtterMidnatt = compareTidspunkt(starterForst.fra, starterSist.til) < 0; return overlapperEtterMidnatt || overlapperFoerMidnatt; } // ingen går over midnatt, så vi overlapper hvis intervall 1 slutter etter intervall 2 starter: // intervall 1: [-----------] // intervall 2: [--------] return compareTidspunkt(starterForst.til, starterSist.fra) > 0; }