Some checks failed
Deploy to Test Environment / deploy-to-test (push) Failing after 54s
101 lines
3.4 KiB
TypeScript
101 lines
3.4 KiB
TypeScript
// src/utils/dateUtils.ts
|
|
import { parseISO, format, isValid, differenceInDays } from 'date-fns';
|
|
|
|
/**
|
|
* Calculates the current year and a simplified week number.
|
|
*
|
|
* Note: This is a simple calculation where week 1 starts on January 1st.
|
|
* For true ISO 8601 week numbers (where week 1 is the first week with a Thursday),
|
|
* a dedicated library like `date-fns` (`getISOWeek` and `getISOWeekYear`) is recommended.
|
|
*
|
|
* @param date The date to calculate the simple week for. Defaults to the current date.
|
|
* @returns An object containing the year and week number.
|
|
*/
|
|
export function calculateSimpleWeekAndYear(date: Date = new Date()): { year: number; week: number } {
|
|
const year = date.getFullYear();
|
|
// Use UTC dates to calculate the difference in days.
|
|
// This avoids issues with Daylight Saving Time (DST) where a day might have 23 or 25 hours,
|
|
// which can cause the millisecond-based calculation to be slightly off (e.g., 149.96 days).
|
|
const startOfYear = Date.UTC(year, 0, 1);
|
|
const current = Date.UTC(year, date.getMonth(), date.getDate());
|
|
const msPerDay = 1000 * 60 * 60 * 24;
|
|
const dayOfYear = (current - startOfYear) / msPerDay;
|
|
// Divide by 7, take the floor to get the zero-based week, and add 1 for a one-based week number.
|
|
const week = Math.floor(dayOfYear / 7) + 1;
|
|
|
|
return { year, week };
|
|
}
|
|
|
|
export const formatShortDate = (dateString: string | null | undefined): string | null => {
|
|
if (!dateString) return null;
|
|
// Using `parseISO` from date-fns is more reliable than `new Date()` for YYYY-MM-DD strings.
|
|
// It correctly interprets the string as a local date, avoiding timezone-related "off-by-one" errors.
|
|
const date = parseISO(dateString);
|
|
if (isValid(date)) {
|
|
return format(date, 'MMM d');
|
|
}
|
|
return null;
|
|
};
|
|
|
|
export const calculateDaysBetween = (
|
|
startDate: string | Date | null | undefined,
|
|
endDate: string | Date | null | undefined,
|
|
): number | null => {
|
|
if (!startDate || !endDate) return null;
|
|
|
|
const start = typeof startDate === 'string' ? parseISO(startDate) : startDate;
|
|
const end = typeof endDate === 'string' ? parseISO(endDate) : endDate;
|
|
|
|
if (!isValid(start) || !isValid(end)) return null;
|
|
|
|
return differenceInDays(end, start);
|
|
};
|
|
|
|
interface DateRangeOptions {
|
|
verbose?: boolean;
|
|
}
|
|
|
|
export const formatDateRange = (
|
|
startDate: string | null | undefined,
|
|
endDate: string | null | undefined,
|
|
options?: DateRangeOptions,
|
|
): string | null => {
|
|
if (!options?.verbose) {
|
|
const start = formatShortDate(startDate);
|
|
const end = formatShortDate(endDate);
|
|
|
|
if (start && end) {
|
|
return start === end ? start : `${start} - ${end}`;
|
|
}
|
|
return start || end || null;
|
|
}
|
|
|
|
// Verbose format logic
|
|
const dateFormat = 'MMMM d, yyyy';
|
|
const formatFn = (dateStr: string | null | undefined) => {
|
|
if (!dateStr) return null;
|
|
const date = parseISO(dateStr);
|
|
return isValid(date) ? format(date, dateFormat) : null;
|
|
};
|
|
|
|
const start = formatFn(startDate);
|
|
const end = formatFn(endDate);
|
|
|
|
if (start && end) {
|
|
return start === end ? `Valid on ${start}` : `Deals valid from ${start} to ${end}`;
|
|
}
|
|
if (start) return `Deals start ${start}`;
|
|
if (end) return `Deals end ${end}`;
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* Returns the current date as an ISO 8601 string (YYYY-MM-DD).
|
|
* Useful for getting "today" without the time component.
|
|
*/
|
|
export const getCurrentDateISOString = (): string => {
|
|
return format(new Date(), 'yyyy-MM-dd');
|
|
};
|
|
|
|
export { calculateSimpleWeekAndYear as getSimpleWeekAndYear };
|