targo-backend/src/common/utils/date-utils.ts

177 lines
6.6 KiB
TypeScript

//lenght of a shift, rouded to nearest 'x' minute
export function computeHours(start: Date, end: Date, roundToMinutes?: number): number {
const diffMs = end.getTime() - start.getTime();
const totalMinutes = diffMs / 60000;
const minutes = roundToMinutes ?
Math.round(totalMinutes / roundToMinutes) * roundToMinutes :
totalMinutes;
return +(minutes / 60).toFixed(2);
}
//round the amount of hours to quarter
export function roundToQuarterHour(hours: number): number {
return Math.round(hours *4) / 4;
}
//fetch firts day of the week (Sunday)
export function getWeekStart(date:Date, firstDayOfWeek = 0): Date {
const d = new Date(date);
const day = d.getDay();
const diff = (day < firstDayOfWeek ? 7 : 0) + (day - firstDayOfWeek);
d.setDate(d.getDate() - diff);
d.setHours(0,0,0,0);
return d;
}
//fetch last day of the week (Saturday)
export function getWeekEnd(startOfWeek: Date): Date {
const d = new Date(startOfWeek);
d.setDate(d.getDate() + 6);
d.setHours(23,59,59,999);
return d;
}
//returns january 1st of the selected date's year
export function getYearStart(date:Date): Date {
return new Date(date.getFullYear(),0,1,0,0,0,0);
}
//to be used to calculate breaks time
export function hoursBetweenSameDay(day: Date, startTime: Date, endTime: Date): number {
const start = new Date(day); start.setHours(startTime.getHours(),
startTime.getMinutes(),
startTime.getSeconds(),
startTime.getMilliseconds());
const end = new Date(day); end.setHours(endTime.getHours(),
endTime.getMinutes(),
endTime.getSeconds(),
endTime.getMilliseconds());
const ms = Math.max(0, end.getTime() - start.getTime());
return ms / 3_600_000; // decimal hours
}
import { BadRequestException } from "@nestjs/common";
import { ANCHOR_ISO, MS_PER_DAY, PERIODS_PER_YEAR, PERIOD_DAYS } from "src/common/utils/constants.utils";
//ensures the week starts from sunday
export function weekStartSunday(date_local: Date): Date {
const start_date = new Date();
start_date.setDate(date_local.getUTCDate() - date_local.getUTCDay());
return start_date;
}
//converts string to HHmm format
export const toStringFromHHmm = (date: Date): string => {
const hh = date.getUTCHours().toString().padStart(2, '0');
const mm = date.getUTCMinutes().toString().padStart(2, '0');
return `${hh}:${mm}`;
}
//converts string to Date format
export const toStringFromDate = (date: Date) =>
date.toISOString().slice(0, 10);
//converts HHmm format to string
export const toDateFromHHmm = (hhmm: string): Date => {
const [hh, mm] = hhmm.split(':').map(Number);
const date = new Date('1970-01-01T00:00:00.000Z');
date.setUTCHours(hh, mm, 0, 0);
return new Date(date);
}
//converts string to HHmm format
export const toHHmmFromDate = (input: Date | string): string => {
const date = new Date(input);
const hh = String(date.getUTCHours()).padStart(2, '0');
const mm = String(date.getUTCMinutes()).padStart(2, '0');
return `${hh}:${mm}`;
}
//converts to Date format from string
export const toDateFromString = (ymd: string | Date): Date => {
return new Date(ymd);
}
export const toUTCDateFromString = (iso: string | Date) => {
const d = typeof iso === 'string' ? new Date(iso + 'T00:00:00.000Z') : iso;
return new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
};
export const sevenDaysFrom = (date: Date | string): Date[] => {
return Array.from({ length: 7 }, (_, i) => {
const d = new Date(date);
d.setUTCDate(d.getUTCDate() + i);
return d;
});
}
export function payYearOfDate(date: string | Date, anchorISO = ANCHOR_ISO): number {
const ANCHOR = toUTCDateFromString(anchorISO);
const d = toUTCDateFromString(date);
const days = Math.floor((+d - +ANCHOR) / MS_PER_DAY);
const cycles = Math.floor(days / (PERIODS_PER_YEAR * PERIOD_DAYS));
return ANCHOR.getUTCFullYear() + 1 + cycles;
}
//compute labels for periods
export function computePeriod(pay_year: number, period_no: number, anchorISO = ANCHOR_ISO) {
const ANCHOR = toUTCDateFromString(anchorISO);
const cycles = pay_year - (ANCHOR.getUTCFullYear() + 1);
const offsetPeriods = cycles * PERIODS_PER_YEAR + (period_no - 1);
const start = new Date(+ANCHOR + offsetPeriods * PERIOD_DAYS * MS_PER_DAY);
const end = new Date(+start + (PERIOD_DAYS - 1) * MS_PER_DAY);
const pay = new Date(end.getTime() + 6 * MS_PER_DAY);
return {
period_no: period_no,
pay_year: pay_year,
payday: toStringFromDate(pay),
period_start: toStringFromDate(start),
period_end: toStringFromDate(end),
label: `${toStringFromDate(start)}.${toStringFromDate(end)}`,
start, end,
};
}
//list of all 26 periods for a full year
export function listPayYear(pay_year: number, anchorISO = ANCHOR_ISO) {
return Array.from({ length: PERIODS_PER_YEAR }, (_, i) => computePeriod(pay_year, i + 1, anchorISO));
}
export const overlaps = (a: { start: Date; end: Date, date?: Date; }, b: { start: Date; end: Date; date?: Date; }) =>
((a.date?.getTime() === b.date?.getTime()) && !(a.end <= b.start || a.start >= b.end));
export const hhmmFromLocal = (d: Date) =>
`${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')}`;
export const toDateOnly = (s: string): Date => {
if (/^\d{4}-\d{2}-\d{2}$/.test(s)) {
const y = Number(s.slice(0,4));
const m = Number(s.slice(5,7)) - 1;
const d = Number(s.slice(8,10));
return new Date(y, m, d, 0, 0, 0, 0);
}
const dt = new Date(s);
if (Number.isNaN(dt.getTime())) throw new BadRequestException(`Invalid date: ${s}`);
return new Date(dt.getFullYear(), dt.getMonth(), dt.getDate(), 0,0,0,0);
};
// export const toStringFromDate = (d: Date) =>
// `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
export const toISOtoDateOnly = (iso: string): Date => {
const date = new Date(iso);
if (Number.isNaN(date.getTime())) {
throw new BadRequestException(`Invalid date: ${iso}`);
}
date.setHours(0, 0, 0, 0);
return date;
};
export const toISODateKey = (date: Date): string => date.toISOString().slice(0, 10);
export const normalizeDates = (dates: string[]): string[] =>
Array.from(new Set(dates.map((iso) => toISODateKey(toISOtoDateOnly(iso)))));