compassmock/src/lib/schedule/business-days.ts
Nicholai aa6230c9d4 feat(schedule): add BuilderTrend parity enhancements
Add two-level tab structure (Schedule/Baseline/Workday Exceptions),
calendar view, enhanced list view with progress rings and initials
avatars, split-pane gantt view, workday exception management with
business day integration, and baseline snapshot comparison.
2026-01-23 20:14:09 -07:00

83 lines
1.8 KiB
TypeScript
Executable File

import { addDays, isWeekend, parseISO, format, isWithinInterval } from "date-fns"
import type { WorkdayExceptionData } from "./types"
function isExceptionDay(
date: Date,
exceptions: WorkdayExceptionData[]
): boolean {
return exceptions.some((ex) => {
const start = parseISO(ex.startDate)
const end = parseISO(ex.endDate)
return isWithinInterval(date, { start, end })
})
}
function isNonWorkday(
date: Date,
exceptions: WorkdayExceptionData[] = []
): boolean {
return isWeekend(date) || isExceptionDay(date, exceptions)
}
export function calculateEndDate(
startDate: string,
workdays: number,
exceptions: WorkdayExceptionData[] = []
): string {
if (workdays <= 0) return startDate
let current = parseISO(startDate)
let remaining = workdays
if (!isNonWorkday(current, exceptions)) {
remaining--
}
while (remaining > 0) {
current = addDays(current, 1)
if (!isNonWorkday(current, exceptions)) {
remaining--
}
}
return format(current, "yyyy-MM-dd")
}
export function countBusinessDays(
startDate: string,
endDate: string,
exceptions: WorkdayExceptionData[] = []
): number {
let current = parseISO(startDate)
const end = parseISO(endDate)
let count = 0
while (current <= end) {
if (!isNonWorkday(current, exceptions)) {
count++
}
current = addDays(current, 1)
}
return count
}
export function addBusinessDays(
date: string,
days: number,
exceptions: WorkdayExceptionData[] = []
): string {
let current = parseISO(date)
let remaining = Math.abs(days)
const direction = days >= 0 ? 1 : -1
while (remaining > 0) {
current = addDays(current, direction)
if (!isNonWorkday(current, exceptions)) {
remaining--
}
}
return format(current, "yyyy-MM-dd")
}