Back to Blog
JavaScriptDatesTimeUtilities

JavaScript Date Manipulation

Master date handling in JavaScript. From native Date to Temporal API to best practices.

B
Bootspring Team
Engineering
January 12, 2021
7 min read

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.000

Date 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.

Share this article

Help spread the word about Bootspring