pratikfrontend / utils /dateUtils.ts
Antaram's picture
Upload 61 files
24c454f verified
Raw
History Blame Contribute Delete
10.7 kB
// Date Utilities with Timezone Support
// Fixes inconsistent date handling across the app
// ============================================
// TYPES
// ============================================
export type DateFormat = 'display' | 'input' | 'iso' | 'short' | 'long';
interface DateFormatOptions {
format?: DateFormat;
includeTime?: boolean;
timezone?: 'local' | 'utc';
}
// ============================================
// CONSTANTS
// ============================================
// Indian Standard Time offset (UTC+5:30)
const IST_OFFSET_HOURS = 5;
const IST_OFFSET_MINUTES = 30;
// ============================================
// TIMEZONE UTILITIES
// ============================================
/**
* Get current date in IST timezone
*/
export const getCurrentDateIST = (): Date => {
const now = new Date();
const utc = now.getTime() + (now.getTimezoneOffset() * 60000);
return new Date(utc + (IST_OFFSET_HOURS * 3600000) + (IST_OFFSET_MINUTES * 60000));
};
/**
* Convert date to IST timezone
*/
export const toIST = (date: Date): Date => {
const utc = date.getTime() + (date.getTimezoneOffset() * 60000);
return new Date(utc + (IST_OFFSET_HOURS * 3600000) + (IST_OFFSET_MINUTES * 60000));
};
/**
* Get start of day in IST
*/
export const getStartOfDayIST = (date: Date = new Date()): Date => {
const ist = toIST(date);
return new Date(ist.getFullYear(), ist.getMonth(), ist.getDate(), 0, 0, 0, 0);
};
/**
* Get end of day in IST
*/
export const getEndOfDayIST = (date: Date = new Date()): Date => {
const ist = toIST(date);
return new Date(ist.getFullYear(), ist.getMonth(), ist.getDate(), 23, 59, 59, 999);
};
// ============================================
// FORMATTING
// ============================================
/**
* Format date to DD/MM/YYYY (Indian format)
*/
export const formatDisplayDate = (dateStr: string | Date): string => {
const date = typeof dateStr === 'string' ? new Date(dateStr) : dateStr;
if (isNaN(date.getTime())) return '-';
return date.toLocaleDateString('en-IN', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
timeZone: 'Asia/Kolkata'
});
};
/**
* Format date to YYYY-MM-DD (input field format)
*/
export const formatInputDate = (dateStr: string | Date): string => {
const date = typeof dateStr === 'string' ? new Date(dateStr) : dateStr;
if (isNaN(date.getTime())) return '';
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
};
/**
* Format date to DD/MM/YY (short format)
*/
export const formatShortDate = (dateStr: string | Date): string => {
const date = typeof dateStr === 'string' ? new Date(dateStr) : dateStr;
if (isNaN(date.getTime())) return '';
const dd = date.getDate().toString().padStart(2, '0');
const mm = (date.getMonth() + 1).toString().padStart(2, '0');
const yy = date.getFullYear().toString().slice(-2);
return `${dd}/${mm}/${yy}`;
};
/**
* Format date with time (DD/MM/YYYY HH:mm)
*/
export const formatDateTime = (dateStr: string | Date): string => {
const date = typeof dateStr === 'string' ? new Date(dateStr) : dateStr;
if (isNaN(date.getTime())) return '-';
const datePart = formatDisplayDate(date);
const timePart = date.toLocaleTimeString('en-IN', {
hour: '2-digit',
minute: '2-digit',
hour12: true,
timeZone: 'Asia/Kolkata'
});
return `${datePart} ${timePart}`;
};
/**
* Format date to long format (e.g., "15 March 2024")
*/
export const formatLongDate = (dateStr: string | Date): string => {
const date = typeof dateStr === 'string' ? new Date(dateStr) : dateStr;
if (isNaN(date.getTime())) return '-';
return date.toLocaleDateString('en-IN', {
day: 'numeric',
month: 'long',
year: 'numeric',
timeZone: 'Asia/Kolkata'
});
};
/**
* Format date in Marathi (e.g., "१५ मार्च २०२४")
*/
export const formatMarathiDate = (dateStr: string | Date): string => {
const date = typeof dateStr === 'string' ? new Date(dateStr) : dateStr;
if (isNaN(date.getTime())) return '-';
return date.toLocaleDateString('mr-IN', {
day: 'numeric',
month: 'long',
year: 'numeric',
timeZone: 'Asia/Kolkata'
});
};
// ============================================
// CONVENIENCE FUNCTIONS
// ============================================
/**
* Get today's date in YYYY-MM-DD format (for input fields)
*/
export const getTodayDate = (): string => {
return formatInputDate(new Date());
};
/**
* Get today's date in DD/MM/YYYY format (for display)
*/
export const getTodayDisplayDate = (): string => {
return formatDisplayDate(new Date());
};
/**
* Parse date string to Date object (handles multiple formats)
*/
export const parseDate = (dateStr: string): Date | null => {
if (!dateStr) return null;
// Try ISO format (YYYY-MM-DD)
if (/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) {
return new Date(dateStr + 'T00:00:00');
}
// Try DD/MM/YYYY format
if (/^\d{2}\/\d{2}\/\d{4}$/.test(dateStr)) {
const [day, month, year] = dateStr.split('/');
return new Date(`${year}-${month}-${day}T00:00:00`);
}
// Try DD/MM/YY format
if (/^\d{2}\/\d{2}\/\d{2}$/.test(dateStr)) {
const [day, month, year] = dateStr.split('/');
return new Date(`20${year}-${month}-${day}T00:00:00`);
}
// Fallback to native parsing
const parsed = new Date(dateStr);
return isNaN(parsed.getTime()) ? null : parsed;
};
// ============================================
// DATE CALCULATIONS
// ============================================
/**
* Add days to a date
*/
export const addDays = (date: Date, days: number): Date => {
const result = new Date(date);
result.setDate(result.getDate() + days);
return result;
};
/**
* Get difference in days between two dates
*/
export const getDaysDifference = (date1: Date, date2: Date): number => {
const oneDay = 24 * 60 * 60 * 1000;
const d1 = new Date(date1.getFullYear(), date1.getMonth(), date1.getDate());
const d2 = new Date(date2.getFullYear(), date2.getMonth(), date2.getDate());
return Math.round(Math.abs((d2.getTime() - d1.getTime()) / oneDay));
};
/**
* Check if date is today
*/
export const isToday = (dateStr: string | Date): boolean => {
const date = typeof dateStr === 'string' ? new Date(dateStr) : dateStr;
const today = new Date();
return (
date.getFullYear() === today.getFullYear() &&
date.getMonth() === today.getMonth() &&
date.getDate() === today.getDate()
);
};
/**
* Check if date is in the past
*/
export const isPastDate = (dateStr: string | Date): boolean => {
const date = typeof dateStr === 'string' ? new Date(dateStr) : dateStr;
const today = getStartOfDayIST();
return date < today;
};
/**
* Check if date is in the future
*/
export const isFutureDate = (dateStr: string | Date): boolean => {
const date = typeof dateStr === 'string' ? new Date(dateStr) : dateStr;
const today = getEndOfDayIST();
return date > today;
};
// ============================================
// FINANCIAL YEAR UTILITIES (India: April-March)
// ============================================
/**
* Get current financial year
*/
export const getCurrentFinancialYear = (): { start: Date; end: Date; label: string } => {
const now = new Date();
const year = now.getFullYear();
const month = now.getMonth(); // 0-indexed
// If before April (month < 3), FY is previous year to current year
// If April or later (month >= 3), FY is current year to next year
const fyStartYear = month < 3 ? year - 1 : year;
const start = new Date(fyStartYear, 3, 1); // April 1
const end = new Date(fyStartYear + 1, 2, 31); // March 31
const label = `FY ${fyStartYear}-${(fyStartYear + 1).toString().slice(-2)}`;
return { start, end, label };
};
/**
* Get all financial years between two dates
*/
export const getFinancialYears = (startDate: Date, endDate: Date): string[] => {
const years: string[] = [];
let current = new Date(startDate);
while (current <= endDate) {
const fy = getCurrentFinancialYear();
const year = current.getMonth() < 3 ? current.getFullYear() - 1 : current.getFullYear();
const label = `FY ${year}-${(year + 1).toString().slice(-2)}`;
if (!years.includes(label)) {
years.push(label);
}
current.setMonth(current.getMonth() + 1);
}
return years;
};
/**
* Check if date falls in a specific financial year
*/
export const isInFinancialYear = (date: Date, fyLabel: string): boolean => {
const match = fyLabel.match(/FY (\d{4})-(\d{2})/);
if (!match) return false;
const startYear = parseInt(match[1]);
const fyStart = new Date(startYear, 3, 1);
const fyEnd = new Date(startYear + 1, 2, 31, 23, 59, 59);
return date >= fyStart && date <= fyEnd;
};
// ============================================
// UNIVERSAL FORMAT FUNCTION
// ============================================
/**
* Format date with options
*/
export const formatDate = (
dateStr: string | Date,
options: DateFormatOptions = {}
): string => {
const { format = 'display', includeTime = false, timezone = 'local' } = options;
let date = typeof dateStr === 'string' ? new Date(dateStr) : dateStr;
if (isNaN(date.getTime())) return '-';
if (timezone === 'utc') {
date = new Date(date.toUTCString());
}
switch (format) {
case 'input':
return formatInputDate(date);
case 'short':
return formatShortDate(date);
case 'long':
return formatLongDate(date);
case 'iso':
return date.toISOString();
default:
if (includeTime) {
return formatDateTime(date);
}
return formatDisplayDate(date);
}
};
export default {
getCurrentDateIST,
toIST,
getStartOfDayIST,
getEndOfDayIST,
formatDisplayDate,
formatInputDate,
formatShortDate,
formatDateTime,
formatLongDate,
formatMarathiDate,
getTodayDate,
getTodayDisplayDate,
parseDate,
addDays,
getDaysDifference,
isToday,
isPastDate,
isFutureDate,
getCurrentFinancialYear,
getFinancialYears,
isInFinancialYear,
formatDate
};