0
# Utility Functions
1
2
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.
3
4
## Capabilities
5
6
### Date Comparison Functions
7
8
Utility functions for comparing Moment.js date objects with specific semantics for date picker use cases.
9
10
```javascript { .api }
11
/**
12
* Check if moment `a` is the same day as moment `b`
13
* @param a - First moment object
14
* @param b - Second moment object
15
* @returns true if both moments represent the same calendar day
16
*/
17
function isSameDay(a: moment.Moment, b: moment.Moment): boolean;
18
19
/**
20
* Check if moment `a` is after or same day as moment `b`
21
* @param a - First moment object
22
* @param b - Second moment object
23
* @returns true if `a` is after or same day as `b`
24
*/
25
function isInclusivelyAfterDay(a: moment.Moment, b: moment.Moment): boolean;
26
27
/**
28
* Check if moment `a` is before or same day as moment `b`
29
* @param a - First moment object
30
* @param b - Second moment object
31
* @returns true if `a` is before or same day as `b`
32
*/
33
function isInclusivelyBeforeDay(a: moment.Moment, b: moment.Moment): boolean;
34
35
/**
36
* Check if moment `b` is the day immediately after moment `a`
37
* @param a - First moment object
38
* @param b - Second moment object
39
* @returns true if `b` is exactly one day after `a`
40
*/
41
function isNextDay(a: moment.Moment, b: moment.Moment): boolean;
42
```
43
44
**Usage Examples:**
45
46
```javascript
47
import {
48
isSameDay,
49
isInclusivelyAfterDay,
50
isInclusivelyBeforeDay,
51
isNextDay
52
} from "react-dates";
53
import moment from "moment";
54
55
// Date comparison examples
56
const today = moment();
57
const tomorrow = moment().add(1, 'day');
58
const yesterday = moment().subtract(1, 'day');
59
60
// Same day comparison
61
console.log(isSameDay(today, moment())); // true
62
console.log(isSameDay(today, tomorrow)); // false
63
64
// Inclusive comparisons (includes same day)
65
console.log(isInclusivelyAfterDay(tomorrow, today)); // true
66
console.log(isInclusivelyAfterDay(today, today)); // true
67
console.log(isInclusivelyBeforeDay(yesterday, today)); // true
68
console.log(isInclusivelyBeforeDay(today, today)); // true
69
70
// Next day check
71
console.log(isNextDay(today, tomorrow)); // true
72
console.log(isNextDay(today, moment().add(2, 'days'))); // false
73
74
// Practical usage in validation
75
function validateDateRange(startDate, endDate) {
76
if (!startDate || !endDate) return false;
77
78
// End date must be after or same as start date
79
return isInclusivelyAfterDay(endDate, startDate);
80
}
81
82
function findNextAvailableDate(currentDate, blockedDates) {
83
let nextDate = currentDate.clone().add(1, 'day');
84
85
while (blockedDates.some(blocked => isSameDay(nextDate, blocked))) {
86
nextDate.add(1, 'day');
87
}
88
89
return nextDate;
90
}
91
92
// Range validation helper
93
function isDateInRange(date, startDate, endDate) {
94
return isInclusivelyAfterDay(date, startDate) &&
95
isInclusivelyBeforeDay(date, endDate);
96
}
97
98
// Consecutive date checker
99
function hasConsecutiveDates(dates) {
100
const sortedDates = dates.sort((a, b) => a.valueOf() - b.valueOf());
101
102
for (let i = 0; i < sortedDates.length - 1; i++) {
103
if (!isNextDay(sortedDates[i], sortedDates[i + 1])) {
104
return false;
105
}
106
}
107
108
return true;
109
}
110
```
111
112
### Date Conversion Functions
113
114
Utilities for converting between different date formats and representations.
115
116
```javascript { .api }
117
/**
118
* Convert date to ISO string format (YYYY-MM-DD)
119
* @param date - Moment object or date string
120
* @param currentFormat - Current format of date string (if date is string)
121
* @returns ISO formatted date string or null if invalid
122
*/
123
function toISODateString(date: moment.Moment | string, currentFormat?: string): string;
124
125
/**
126
* Convert date to localized string format
127
* @param date - Moment object or date string
128
* @param currentFormat - Current format of date string (if date is string)
129
* @returns Localized date string or null if invalid
130
*/
131
function toLocalizedDateString(date: moment.Moment | string, currentFormat?: string): string;
132
133
/**
134
* Convert date string to moment object with validation
135
* @param dateString - Date string to parse
136
* @param customFormat - Custom format for parsing (optional)
137
* @returns Moment object or null if invalid
138
*/
139
function toMomentObject(dateString: string, customFormat?: string): moment.Moment | null;
140
```
141
142
**Usage Examples:**
143
144
```javascript
145
import {
146
toISODateString,
147
toLocalizedDateString,
148
toMomentObject
149
} from "react-dates";
150
import moment from "moment";
151
152
// ISO date string conversion
153
const today = moment();
154
console.log(toISODateString(today)); // "2023-12-25"
155
156
// From custom format string
157
console.log(toISODateString("12/25/2023", "MM/DD/YYYY")); // "2023-12-25"
158
console.log(toISODateString("Dec 25, 2023", "MMM DD, YYYY")); // "2023-12-25"
159
160
// Localized string conversion
161
console.log(toLocalizedDateString(today)); // Depends on locale, e.g., "12/25/2023"
162
console.log(toLocalizedDateString("2023-12-25")); // "12/25/2023"
163
164
// String to moment conversion
165
const momentObj = toMomentObject("2023-12-25");
166
console.log(momentObj?.format("MMMM DD, YYYY")); // "December 25, 2023"
167
168
// Custom format parsing
169
const customDate = toMomentObject("25/12/2023", "DD/MM/YYYY");
170
console.log(customDate?.format("YYYY-MM-DD")); // "2023-12-25"
171
172
// Invalid date handling
173
const invalid = toMomentObject("invalid-date");
174
console.log(invalid); // null
175
176
// Practical usage examples
177
function formatDateForAPI(date) {
178
if (moment.isMoment(date)) {
179
return toISODateString(date);
180
}
181
return null;
182
}
183
184
function formatDateForDisplay(date) {
185
if (moment.isMoment(date)) {
186
return toLocalizedDateString(date);
187
}
188
return "";
189
}
190
191
function parseUserInput(dateString, expectedFormat = "MM/DD/YYYY") {
192
const momentObj = toMomentObject(dateString, expectedFormat);
193
194
if (momentObj) {
195
return {
196
isValid: true,
197
date: momentObj,
198
iso: toISODateString(momentObj),
199
display: toLocalizedDateString(momentObj)
200
};
201
}
202
203
return {
204
isValid: false,
205
date: null,
206
iso: null,
207
display: ""
208
};
209
}
210
211
// Date range serialization
212
function serializeDateRange(startDate, endDate) {
213
return {
214
startDate: startDate ? toISODateString(startDate) : null,
215
endDate: endDate ? toISODateString(endDate) : null
216
};
217
}
218
219
function deserializeDateRange(serialized) {
220
return {
221
startDate: serialized.startDate ? toMomentObject(serialized.startDate) : null,
222
endDate: serialized.endDate ? toMomentObject(serialized.endDate) : null
223
};
224
}
225
```
226
227
## Common Date Utility Patterns
228
229
### Date Range Validation
230
231
```javascript
232
import {
233
isSameDay,
234
isInclusivelyAfterDay,
235
isInclusivelyBeforeDay
236
} from "react-dates";
237
238
// Complete date range validator
239
function validateDateRange(startDate, endDate, options = {}) {
240
const { minDate, maxDate, minimumNights = 0 } = options;
241
242
if (!startDate || !endDate) {
243
return { isValid: false, error: "Both dates are required" };
244
}
245
246
// End must be after start
247
if (!isInclusivelyAfterDay(endDate, startDate)) {
248
return { isValid: false, error: "End date must be after start date" };
249
}
250
251
// Check minimum nights
252
if (endDate.diff(startDate, 'days') < minimumNights) {
253
return {
254
isValid: false,
255
error: `Minimum ${minimumNights} night(s) required`
256
};
257
}
258
259
// Check against min/max constraints
260
if (minDate && isInclusivelyBeforeDay(startDate, minDate)) {
261
return { isValid: false, error: "Start date is too early" };
262
}
263
264
if (maxDate && isInclusivelyAfterDay(endDate, maxDate)) {
265
return { isValid: false, error: "End date is too late" };
266
}
267
268
return { isValid: true, error: null };
269
}
270
271
// Usage
272
const validation = validateDateRange(
273
moment("2023-12-25"),
274
moment("2023-12-27"),
275
{ minimumNights: 2, minDate: moment() }
276
);
277
278
if (!validation.isValid) {
279
console.error(validation.error);
280
}
281
```
282
283
### Date List Processing
284
285
```javascript
286
import { isSameDay, isInclusivelyAfterDay } from "react-dates";
287
288
// Filter and sort date lists
289
function processDates(dates, options = {}) {
290
const { filterPast = false, sort = true, unique = true } = options;
291
292
let processedDates = [...dates];
293
294
// Remove past dates if requested
295
if (filterPast) {
296
const today = moment().startOf('day');
297
processedDates = processedDates.filter(date =>
298
isInclusivelyAfterDay(date, today)
299
);
300
}
301
302
// Remove duplicates if requested
303
if (unique) {
304
processedDates = processedDates.filter((date, index, array) =>
305
array.findIndex(d => isSameDay(d, date)) === index
306
);
307
}
308
309
// Sort if requested
310
if (sort) {
311
processedDates.sort((a, b) => a.valueOf() - b.valueOf());
312
}
313
314
return processedDates;
315
}
316
317
// Find date ranges in a list
318
function findDateRanges(dates) {
319
const sortedDates = processDates(dates, { sort: true, unique: true });
320
const ranges = [];
321
let currentRange = null;
322
323
sortedDates.forEach(date => {
324
if (!currentRange) {
325
currentRange = { start: date, end: date };
326
} else if (isNextDay(currentRange.end, date)) {
327
currentRange.end = date;
328
} else {
329
ranges.push(currentRange);
330
currentRange = { start: date, end: date };
331
}
332
});
333
334
if (currentRange) {
335
ranges.push(currentRange);
336
}
337
338
return ranges;
339
}
340
```
341
342
### Format Conversion Pipeline
343
344
```javascript
345
import { toISODateString, toLocalizedDateString, toMomentObject } from "react-dates";
346
347
// Comprehensive date format converter
348
class DateConverter {
349
static formats = {
350
ISO: 'YYYY-MM-DD',
351
US: 'MM/DD/YYYY',
352
EU: 'DD/MM/YYYY',
353
DISPLAY: 'MMM DD, YYYY',
354
API: 'YYYY-MM-DD'
355
};
356
357
static convert(date, fromFormat, toFormat) {
358
// Parse input
359
let momentObj;
360
if (moment.isMoment(date)) {
361
momentObj = date;
362
} else if (typeof date === 'string') {
363
momentObj = toMomentObject(date, fromFormat);
364
} else {
365
return null;
366
}
367
368
if (!momentObj) return null;
369
370
// Convert to target format
371
switch (toFormat) {
372
case 'ISO':
373
return toISODateString(momentObj);
374
case 'LOCALIZED':
375
return toLocalizedDateString(momentObj);
376
default:
377
return momentObj.format(toFormat);
378
}
379
}
380
381
static batch(dates, fromFormat, toFormat) {
382
return dates.map(date => this.convert(date, fromFormat, toFormat))
383
.filter(Boolean);
384
}
385
}
386
387
// Usage examples
388
const dates = ['12/25/2023', '01/01/2024', '02/14/2024'];
389
const isoDates = DateConverter.batch(dates, 'MM/DD/YYYY', 'ISO');
390
console.log(isoDates); // ['2023-12-25', '2024-01-01', '2024-02-14']
391
392
const displayDates = DateConverter.batch(dates, 'MM/DD/YYYY', 'MMM DD, YYYY');
393
console.log(displayDates); // ['Dec 25, 2023', 'Jan 01, 2024', 'Feb 14, 2024']
394
```
395
396
## Error Handling
397
398
All utility functions handle invalid dates gracefully:
399
400
```javascript
401
// Safe date operations
402
function safeOperation(dateA, dateB, operation) {
403
try {
404
if (!moment.isMoment(dateA) || !moment.isMoment(dateB)) {
405
return false;
406
}
407
408
if (!dateA.isValid() || !dateB.isValid()) {
409
return false;
410
}
411
412
return operation(dateA, dateB);
413
} catch (error) {
414
console.warn('Date operation failed:', error);
415
return false;
416
}
417
}
418
419
// Usage
420
const result = safeOperation(dateA, dateB, isSameDay);
421
```
422
423
## Performance Considerations
424
425
The utility functions are optimized for performance:
426
427
- **Efficient Comparisons**: Direct moment comparison without format conversion
428
- **Null Handling**: Early returns for null/undefined values
429
- **Validation Caching**: Results can be cached for repeated operations
430
- **Memory Efficient**: No intermediate object creation in comparisons
431
432
```javascript
433
// Performance-optimized date range checking
434
function optimizedDateInRange(date, startDate, endDate) {
435
// Early returns for null values
436
if (!date || !startDate || !endDate) return false;
437
438
// Single comparison operation
439
return date.valueOf() >= startDate.valueOf() &&
440
date.valueOf() <= endDate.valueOf();
441
}
442
```