Working with dates in JavaScript requires understanding quirks and patterns. Here's a comprehensive guide.
Creating Dates#
1// Current date and time
2const now = new Date();
3
4// From string (ISO 8601 preferred)
5const fromISO = new Date('2024-03-15T14:30:00Z');
6const fromDate = new Date('2024-03-15');
7
8// From components (months are 0-indexed!)
9const fromParts = new Date(2024, 2, 15, 14, 30, 0); // March 15, 2024
10
11// From timestamp (milliseconds since Unix epoch)
12const fromTimestamp = new Date(1710510600000);
13
14// UTC date
15const utc = new Date(Date.UTC(2024, 2, 15, 14, 30, 0));
16
17// Parse with explicit timezone
18const withTimezone = new Date('2024-03-15T14:30:00-05:00');Getters and Setters#
1const date = new Date('2024-03-15T14:30:45.123Z');
2
3// Getters (local time)
4date.getFullYear(); // 2024
5date.getMonth(); // 2 (March, 0-indexed)
6date.getDate(); // 15
7date.getDay(); // 5 (Friday, 0 = Sunday)
8date.getHours(); // Varies by timezone
9date.getMinutes(); // 30
10date.getSeconds(); // 45
11date.getMilliseconds(); // 123
12
13// Getters (UTC)
14date.getUTCFullYear(); // 2024
15date.getUTCMonth(); // 2
16date.getUTCDate(); // 15
17date.getUTCHours(); // 14
18date.getUTCMinutes(); // 30
19
20// Timestamp
21date.getTime(); // 1710510645123
22Date.now(); // Current timestamp
23
24// Setters (mutate the date!)
25const mutable = new Date();
26mutable.setFullYear(2025);
27mutable.setMonth(5); // June
28mutable.setDate(20);
29mutable.setHours(12, 0, 0, 0); // 12:00:00.000Date Arithmetic#
1// Add days
2function addDays(date, days) {
3 const result = new Date(date);
4 result.setDate(result.getDate() + days);
5 return result;
6}
7
8// Add months (handles month overflow)
9function addMonths(date, months) {
10 const result = new Date(date);
11 result.setMonth(result.getMonth() + months);
12 return result;
13}
14
15// Add years
16function addYears(date, years) {
17 const result = new Date(date);
18 result.setFullYear(result.getFullYear() + years);
19 return result;
20}
21
22// Difference in days
23function diffInDays(date1, date2) {
24 const msPerDay = 24 * 60 * 60 * 1000;
25 return Math.round((date2 - date1) / msPerDay);
26}
27
28// Difference in months
29function diffInMonths(date1, date2) {
30 return (
31 (date2.getFullYear() - date1.getFullYear()) * 12 +
32 date2.getMonth() - date1.getMonth()
33 );
34}
35
36// Usage
37const today = new Date();
38const nextWeek = addDays(today, 7);
39const nextMonth = addMonths(today, 1);
40const nextYear = addYears(today, 1);Formatting Dates#
1// Built-in methods
2const date = new Date('2024-03-15T14:30:00');
3
4date.toISOString(); // '2024-03-15T14:30:00.000Z'
5date.toDateString(); // 'Fri Mar 15 2024'
6date.toTimeString(); // '14:30:00 GMT-0400'
7date.toLocaleDateString(); // '3/15/2024' (US locale)
8date.toLocaleTimeString(); // '2:30:00 PM'
9date.toLocaleString(); // '3/15/2024, 2:30:00 PM'
10
11// Intl.DateTimeFormat
12const formatter = new Intl.DateTimeFormat('en-US', {
13 year: 'numeric',
14 month: 'long',
15 day: 'numeric',
16 weekday: 'long',
17});
18formatter.format(date); // 'Friday, March 15, 2024'
19
20// Custom format function
21function formatDate(date, format) {
22 const map = {
23 'YYYY': date.getFullYear(),
24 'MM': String(date.getMonth() + 1).padStart(2, '0'),
25 'DD': String(date.getDate()).padStart(2, '0'),
26 'HH': String(date.getHours()).padStart(2, '0'),
27 'mm': String(date.getMinutes()).padStart(2, '0'),
28 'ss': String(date.getSeconds()).padStart(2, '0'),
29 };
30
31 return format.replace(/YYYY|MM|DD|HH|mm|ss/g, match => map[match]);
32}
33
34formatDate(date, 'YYYY-MM-DD'); // '2024-03-15'
35formatDate(date, 'DD/MM/YYYY HH:mm'); // '15/03/2024 14:30'Comparison#
1const date1 = new Date('2024-03-15');
2const date2 = new Date('2024-03-20');
3
4// Compare timestamps
5date1 < date2; // true
6date1 > date2; // false
7date1.getTime() === date2.getTime(); // false
8
9// Check same day
10function isSameDay(d1, d2) {
11 return (
12 d1.getFullYear() === d2.getFullYear() &&
13 d1.getMonth() === d2.getMonth() &&
14 d1.getDate() === d2.getDate()
15 );
16}
17
18// Check if date is between
19function isBetween(date, start, end) {
20 return date >= start && date <= end;
21}
22
23// Check if past/future
24function isPast(date) {
25 return date < new Date();
26}
27
28function isFuture(date) {
29 return date > new Date();
30}
31
32// Check if today
33function isToday(date) {
34 return isSameDay(date, new Date());
35}Start/End of Periods#
1// Start of day
2function startOfDay(date) {
3 const result = new Date(date);
4 result.setHours(0, 0, 0, 0);
5 return result;
6}
7
8// End of day
9function endOfDay(date) {
10 const result = new Date(date);
11 result.setHours(23, 59, 59, 999);
12 return result;
13}
14
15// Start of month
16function startOfMonth(date) {
17 const result = new Date(date);
18 result.setDate(1);
19 result.setHours(0, 0, 0, 0);
20 return result;
21}
22
23// End of month
24function endOfMonth(date) {
25 const result = new Date(date);
26 result.setMonth(result.getMonth() + 1);
27 result.setDate(0);
28 result.setHours(23, 59, 59, 999);
29 return result;
30}
31
32// Start of week (Sunday)
33function startOfWeek(date) {
34 const result = new Date(date);
35 const day = result.getDay();
36 result.setDate(result.getDate() - day);
37 result.setHours(0, 0, 0, 0);
38 return result;
39}
40
41// Start of year
42function startOfYear(date) {
43 return new Date(date.getFullYear(), 0, 1);
44}Timezone Handling#
1// Get timezone offset in minutes
2const offset = new Date().getTimezoneOffset(); // e.g., 240 for UTC-4
3
4// Convert to different timezone display
5function toTimezone(date, timezone) {
6 return new Intl.DateTimeFormat('en-US', {
7 timeZone: timezone,
8 year: 'numeric',
9 month: '2-digit',
10 day: '2-digit',
11 hour: '2-digit',
12 minute: '2-digit',
13 second: '2-digit',
14 hour12: false,
15 }).format(date);
16}
17
18toTimezone(new Date(), 'America/New_York');
19toTimezone(new Date(), 'Europe/London');
20toTimezone(new Date(), 'Asia/Tokyo');
21
22// Parse date in specific timezone
23function parseInTimezone(dateStr, timezone) {
24 // Create formatter for the timezone
25 const formatter = new Intl.DateTimeFormat('en-US', {
26 timeZone: timezone,
27 year: 'numeric',
28 month: 'numeric',
29 day: 'numeric',
30 hour: 'numeric',
31 minute: 'numeric',
32 second: 'numeric',
33 hour12: false,
34 });
35
36 // This is a simplified approach - for production use a library
37 const date = new Date(dateStr);
38 return date;
39}Working with UTC#
1// Create UTC date
2const utcDate = new Date(Date.UTC(2024, 2, 15, 14, 30, 0));
3
4// Get UTC components
5const year = utcDate.getUTCFullYear();
6const month = utcDate.getUTCMonth();
7const day = utcDate.getUTCDate();
8const hours = utcDate.getUTCHours();
9
10// Convert local to UTC
11function toUTC(date) {
12 return new Date(date.toISOString());
13}
14
15// Get current UTC time
16function nowUTC() {
17 const now = new Date();
18 return new Date(
19 Date.UTC(
20 now.getUTCFullYear(),
21 now.getUTCMonth(),
22 now.getUTCDate(),
23 now.getUTCHours(),
24 now.getUTCMinutes(),
25 now.getUTCSeconds()
26 )
27 );
28}Common Utilities#
1// Days in month
2function getDaysInMonth(year, month) {
3 return new Date(year, month + 1, 0).getDate();
4}
5
6// Is leap year
7function isLeapYear(year) {
8 return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
9}
10
11// Get week number (ISO)
12function getWeekNumber(date) {
13 const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
14 const dayNum = d.getUTCDay() || 7;
15 d.setUTCDate(d.getUTCDate() + 4 - dayNum);
16 const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
17 return Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
18}
19
20// Get quarter
21function getQuarter(date) {
22 return Math.floor(date.getMonth() / 3) + 1;
23}
24
25// Format relative time
26function formatRelative(date) {
27 const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
28 const now = new Date();
29 const diffMs = date - now;
30 const diffSecs = Math.round(diffMs / 1000);
31 const diffMins = Math.round(diffSecs / 60);
32 const diffHours = Math.round(diffMins / 60);
33 const diffDays = Math.round(diffHours / 24);
34
35 if (Math.abs(diffSecs) < 60) return rtf.format(diffSecs, 'second');
36 if (Math.abs(diffMins) < 60) return rtf.format(diffMins, 'minute');
37 if (Math.abs(diffHours) < 24) return rtf.format(diffHours, 'hour');
38 return rtf.format(diffDays, 'day');
39}Validation#
1// Check if valid date
2function isValidDate(date) {
3 return date instanceof Date && !isNaN(date.getTime());
4}
5
6// Parse and validate
7function parseDate(str) {
8 const date = new Date(str);
9 if (!isValidDate(date)) {
10 throw new Error(`Invalid date: ${str}`);
11 }
12 return date;
13}
14
15// Validate date components
16function isValidDateComponents(year, month, day) {
17 const date = new Date(year, month, day);
18 return (
19 date.getFullYear() === year &&
20 date.getMonth() === month &&
21 date.getDate() === day
22 );
23}
24
25// Validate range
26function isInRange(date, min, max) {
27 return date >= min && date <= max;
28}Date Range Generation#
1// Generate date range
2function* dateRange(start, end) {
3 const current = new Date(start);
4 while (current <= end) {
5 yield new Date(current);
6 current.setDate(current.getDate() + 1);
7 }
8}
9
10// Get all dates in month
11function getDatesInMonth(year, month) {
12 const start = new Date(year, month, 1);
13 const end = new Date(year, month + 1, 0);
14 return [...dateRange(start, end)];
15}
16
17// Get weekdays between dates
18function getWeekdays(start, end) {
19 const dates = [];
20 const current = new Date(start);
21
22 while (current <= end) {
23 const day = current.getDay();
24 if (day !== 0 && day !== 6) {
25 dates.push(new Date(current));
26 }
27 current.setDate(current.getDate() + 1);
28 }
29
30 return dates;
31}Best Practices#
Creating Dates:
✓ Use ISO 8601 format for strings
✓ Remember months are 0-indexed
✓ Be explicit about timezone
✓ Use Date.UTC for UTC dates
Manipulation:
✓ Always create new Date objects (immutability)
✓ Use setters carefully (they mutate)
✓ Handle month overflow correctly
✓ Test edge cases (DST, leap years)
Formatting:
✓ Use Intl.DateTimeFormat for localization
✓ Store dates in UTC
✓ Display in user's timezone
✓ Use ISO format for APIs
Comparison:
✓ Compare timestamps, not objects
✓ Normalize to same timezone
✓ Consider start/end of day
✓ Handle invalid dates
Conclusion#
JavaScript date handling requires attention to timezones, zero-indexed months, and mutability. Use native Date for simple cases, Intl for formatting, and consider libraries like date-fns for complex operations. Always store in UTC and display in local time.