A responsive and accessible date range picker component built with React
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Date comparison and conversion utilities for working with Moment.js objects in React Dates. These functions provide consistent date handling and validation throughout the library.
Utility functions for comparing Moment.js date objects with specific semantics for date picker use cases.
/**
* Check if moment `a` is the same day as moment `b`
* @param a - First moment object
* @param b - Second moment object
* @returns true if both moments represent the same calendar day
*/
function isSameDay(a: moment.Moment, b: moment.Moment): boolean;
/**
* Check if moment `a` is after or same day as moment `b`
* @param a - First moment object
* @param b - Second moment object
* @returns true if `a` is after or same day as `b`
*/
function isInclusivelyAfterDay(a: moment.Moment, b: moment.Moment): boolean;
/**
* Check if moment `a` is before or same day as moment `b`
* @param a - First moment object
* @param b - Second moment object
* @returns true if `a` is before or same day as `b`
*/
function isInclusivelyBeforeDay(a: moment.Moment, b: moment.Moment): boolean;
/**
* Check if moment `b` is the day immediately after moment `a`
* @param a - First moment object
* @param b - Second moment object
* @returns true if `b` is exactly one day after `a`
*/
function isNextDay(a: moment.Moment, b: moment.Moment): boolean;Usage Examples:
import {
isSameDay,
isInclusivelyAfterDay,
isInclusivelyBeforeDay,
isNextDay
} from "react-dates";
import moment from "moment";
// Date comparison examples
const today = moment();
const tomorrow = moment().add(1, 'day');
const yesterday = moment().subtract(1, 'day');
// Same day comparison
console.log(isSameDay(today, moment())); // true
console.log(isSameDay(today, tomorrow)); // false
// Inclusive comparisons (includes same day)
console.log(isInclusivelyAfterDay(tomorrow, today)); // true
console.log(isInclusivelyAfterDay(today, today)); // true
console.log(isInclusivelyBeforeDay(yesterday, today)); // true
console.log(isInclusivelyBeforeDay(today, today)); // true
// Next day check
console.log(isNextDay(today, tomorrow)); // true
console.log(isNextDay(today, moment().add(2, 'days'))); // false
// Practical usage in validation
function validateDateRange(startDate, endDate) {
if (!startDate || !endDate) return false;
// End date must be after or same as start date
return isInclusivelyAfterDay(endDate, startDate);
}
function findNextAvailableDate(currentDate, blockedDates) {
let nextDate = currentDate.clone().add(1, 'day');
while (blockedDates.some(blocked => isSameDay(nextDate, blocked))) {
nextDate.add(1, 'day');
}
return nextDate;
}
// Range validation helper
function isDateInRange(date, startDate, endDate) {
return isInclusivelyAfterDay(date, startDate) &&
isInclusivelyBeforeDay(date, endDate);
}
// Consecutive date checker
function hasConsecutiveDates(dates) {
const sortedDates = dates.sort((a, b) => a.valueOf() - b.valueOf());
for (let i = 0; i < sortedDates.length - 1; i++) {
if (!isNextDay(sortedDates[i], sortedDates[i + 1])) {
return false;
}
}
return true;
}Utilities for converting between different date formats and representations.
/**
* Convert date to ISO string format (YYYY-MM-DD)
* @param date - Moment object or date string
* @param currentFormat - Current format of date string (if date is string)
* @returns ISO formatted date string or null if invalid
*/
function toISODateString(date: moment.Moment | string, currentFormat?: string): string;
/**
* Convert date to localized string format
* @param date - Moment object or date string
* @param currentFormat - Current format of date string (if date is string)
* @returns Localized date string or null if invalid
*/
function toLocalizedDateString(date: moment.Moment | string, currentFormat?: string): string;
/**
* Convert date string to moment object with validation
* @param dateString - Date string to parse
* @param customFormat - Custom format for parsing (optional)
* @returns Moment object or null if invalid
*/
function toMomentObject(dateString: string, customFormat?: string): moment.Moment | null;Usage Examples:
import {
toISODateString,
toLocalizedDateString,
toMomentObject
} from "react-dates";
import moment from "moment";
// ISO date string conversion
const today = moment();
console.log(toISODateString(today)); // "2023-12-25"
// From custom format string
console.log(toISODateString("12/25/2023", "MM/DD/YYYY")); // "2023-12-25"
console.log(toISODateString("Dec 25, 2023", "MMM DD, YYYY")); // "2023-12-25"
// Localized string conversion
console.log(toLocalizedDateString(today)); // Depends on locale, e.g., "12/25/2023"
console.log(toLocalizedDateString("2023-12-25")); // "12/25/2023"
// String to moment conversion
const momentObj = toMomentObject("2023-12-25");
console.log(momentObj?.format("MMMM DD, YYYY")); // "December 25, 2023"
// Custom format parsing
const customDate = toMomentObject("25/12/2023", "DD/MM/YYYY");
console.log(customDate?.format("YYYY-MM-DD")); // "2023-12-25"
// Invalid date handling
const invalid = toMomentObject("invalid-date");
console.log(invalid); // null
// Practical usage examples
function formatDateForAPI(date) {
if (moment.isMoment(date)) {
return toISODateString(date);
}
return null;
}
function formatDateForDisplay(date) {
if (moment.isMoment(date)) {
return toLocalizedDateString(date);
}
return "";
}
function parseUserInput(dateString, expectedFormat = "MM/DD/YYYY") {
const momentObj = toMomentObject(dateString, expectedFormat);
if (momentObj) {
return {
isValid: true,
date: momentObj,
iso: toISODateString(momentObj),
display: toLocalizedDateString(momentObj)
};
}
return {
isValid: false,
date: null,
iso: null,
display: ""
};
}
// Date range serialization
function serializeDateRange(startDate, endDate) {
return {
startDate: startDate ? toISODateString(startDate) : null,
endDate: endDate ? toISODateString(endDate) : null
};
}
function deserializeDateRange(serialized) {
return {
startDate: serialized.startDate ? toMomentObject(serialized.startDate) : null,
endDate: serialized.endDate ? toMomentObject(serialized.endDate) : null
};
}import {
isSameDay,
isInclusivelyAfterDay,
isInclusivelyBeforeDay
} from "react-dates";
// Complete date range validator
function validateDateRange(startDate, endDate, options = {}) {
const { minDate, maxDate, minimumNights = 0 } = options;
if (!startDate || !endDate) {
return { isValid: false, error: "Both dates are required" };
}
// End must be after start
if (!isInclusivelyAfterDay(endDate, startDate)) {
return { isValid: false, error: "End date must be after start date" };
}
// Check minimum nights
if (endDate.diff(startDate, 'days') < minimumNights) {
return {
isValid: false,
error: `Minimum ${minimumNights} night(s) required`
};
}
// Check against min/max constraints
if (minDate && isInclusivelyBeforeDay(startDate, minDate)) {
return { isValid: false, error: "Start date is too early" };
}
if (maxDate && isInclusivelyAfterDay(endDate, maxDate)) {
return { isValid: false, error: "End date is too late" };
}
return { isValid: true, error: null };
}
// Usage
const validation = validateDateRange(
moment("2023-12-25"),
moment("2023-12-27"),
{ minimumNights: 2, minDate: moment() }
);
if (!validation.isValid) {
console.error(validation.error);
}import { isSameDay, isInclusivelyAfterDay } from "react-dates";
// Filter and sort date lists
function processDates(dates, options = {}) {
const { filterPast = false, sort = true, unique = true } = options;
let processedDates = [...dates];
// Remove past dates if requested
if (filterPast) {
const today = moment().startOf('day');
processedDates = processedDates.filter(date =>
isInclusivelyAfterDay(date, today)
);
}
// Remove duplicates if requested
if (unique) {
processedDates = processedDates.filter((date, index, array) =>
array.findIndex(d => isSameDay(d, date)) === index
);
}
// Sort if requested
if (sort) {
processedDates.sort((a, b) => a.valueOf() - b.valueOf());
}
return processedDates;
}
// Find date ranges in a list
function findDateRanges(dates) {
const sortedDates = processDates(dates, { sort: true, unique: true });
const ranges = [];
let currentRange = null;
sortedDates.forEach(date => {
if (!currentRange) {
currentRange = { start: date, end: date };
} else if (isNextDay(currentRange.end, date)) {
currentRange.end = date;
} else {
ranges.push(currentRange);
currentRange = { start: date, end: date };
}
});
if (currentRange) {
ranges.push(currentRange);
}
return ranges;
}import { toISODateString, toLocalizedDateString, toMomentObject } from "react-dates";
// Comprehensive date format converter
class DateConverter {
static formats = {
ISO: 'YYYY-MM-DD',
US: 'MM/DD/YYYY',
EU: 'DD/MM/YYYY',
DISPLAY: 'MMM DD, YYYY',
API: 'YYYY-MM-DD'
};
static convert(date, fromFormat, toFormat) {
// Parse input
let momentObj;
if (moment.isMoment(date)) {
momentObj = date;
} else if (typeof date === 'string') {
momentObj = toMomentObject(date, fromFormat);
} else {
return null;
}
if (!momentObj) return null;
// Convert to target format
switch (toFormat) {
case 'ISO':
return toISODateString(momentObj);
case 'LOCALIZED':
return toLocalizedDateString(momentObj);
default:
return momentObj.format(toFormat);
}
}
static batch(dates, fromFormat, toFormat) {
return dates.map(date => this.convert(date, fromFormat, toFormat))
.filter(Boolean);
}
}
// Usage examples
const dates = ['12/25/2023', '01/01/2024', '02/14/2024'];
const isoDates = DateConverter.batch(dates, 'MM/DD/YYYY', 'ISO');
console.log(isoDates); // ['2023-12-25', '2024-01-01', '2024-02-14']
const displayDates = DateConverter.batch(dates, 'MM/DD/YYYY', 'MMM DD, YYYY');
console.log(displayDates); // ['Dec 25, 2023', 'Jan 01, 2024', 'Feb 14, 2024']All utility functions handle invalid dates gracefully:
// Safe date operations
function safeOperation(dateA, dateB, operation) {
try {
if (!moment.isMoment(dateA) || !moment.isMoment(dateB)) {
return false;
}
if (!dateA.isValid() || !dateB.isValid()) {
return false;
}
return operation(dateA, dateB);
} catch (error) {
console.warn('Date operation failed:', error);
return false;
}
}
// Usage
const result = safeOperation(dateA, dateB, isSameDay);The utility functions are optimized for performance:
// Performance-optimized date range checking
function optimizedDateInRange(date, startDate, endDate) {
// Early returns for null values
if (!date || !startDate || !endDate) return false;
// Single comparison operation
return date.valueOf() >= startDate.valueOf() &&
date.valueOf() <= endDate.valueOf();
}Install with Tessl CLI
npx tessl i tessl/npm-react-dates