import {isAfter, isBefore, isWithinInterval, startOfDay} from 'date-fns'; export type OnlyDateFormat = string; // YYYY-MM-DD export type OnlyDateUnits = { date: number; month: number; year: number; }; const withBoundaries = (date: Date, min: Date, max: Date) => { if (isBefore(date, min)) { date = min; } else if (isAfter(date, max)) { date = max; } return date; }; const toUnits = (date: OnlyDateFormat | Date): OnlyDateUnits => { let dateObj = new Date(date); return { year: dateObj.getFullYear(), month: dateObj.getMonth(), date: dateObj.getDate(), }; }; const inRange = (units: OnlyDateUnits, start: Date, end: Date) => { return isWithinInterval(toDate(units), { start: startOfDay(start), end: startOfDay(end), }); }; const toDate = (units: OnlyDateUnits) => { return new Date(units.year, units.month, units.date); }; const toOnlyDateFormat = (units: OnlyDateUnits): OnlyDateFormat => { const date = new Date(units.year, units.month, units.date); const year = date.getFullYear(); const month = date.getMonth() + 1; // getMonth() returns 0-11 const day = date.getDate(); // Pad single digit month and day with leading zeros const monthFormatted = month < 10 ? `0${month}` : month; const dayFormatted = day < 10 ? `0${day}` : day; return `${year}-${monthFormatted}-${dayFormatted}`; }; const getDaysInMonth = (year: number, month: number): number => { return new Date(year, month + 1, 0).getDate(); }; export type DateUnitType = 'date' | 'month' | 'year'; export type DateLocale = { locale: string; }; const getSortedDateUnitPositions = (locale: string) => { const formatter = new Intl.DateTimeFormat(locale, { year: 'numeric', month: 'numeric', day: 'numeric', }); const parts = formatter.formatToParts(new Date()); const orderMap: Record = { day: 'date', month: 'month', year: 'year', }; // Создаем массив с правильным порядком элементов const order: DateUnitType[] = []; parts.forEach((part) => { // part - это объект {type: string, value: string} if (part.type in orderMap) { order.push(orderMap[part.type as keyof typeof orderMap]!); } }); return order; }; const getLocalizedMonthNames = (locale: string): string[] => { const monthNames: string[] = []; for (let monthIndex = 0; monthIndex < DateUtils.MONTH_COUNT; monthIndex++) { const date = new Date(2025, monthIndex, 1); // Создаем дату для каждого месяца const formatter = new Intl.DateTimeFormat(locale, { month: 'long', }); const monthName = formatter.format(date); monthNames.push(monthName); } return monthNames; }; const isFirstUnitPosition = (list: DateUnitType[], search: DateUnitType) => { return list[0] === search; }; const isLastUnitPosition = (list: DateUnitType[], search: DateUnitType) => { return list.at(-1) === search; }; export const DateUtils = { MONTH_COUNT: 12, toUnits, toDate, toOnlyDateFormat, inRange, withBoundaries, getDaysInMonth, getSortedDateUnitPositions, getLocalizedMonthNames, isFirstUnitPosition, isLastUnitPosition, };