Back to Blog
JavaScriptDateTimeFundamentals

JavaScript Date Handling Guide

Master JavaScript Date objects for parsing, formatting, and manipulating dates.

B
Bootspring Team
Engineering
July 23, 2018
6 min read

Working with dates in JavaScript requires understanding the Date object and its quirks. Here's a comprehensive guide.

Creating Dates#

1// Current date and time 2const now = new Date(); 3 4// From timestamp (milliseconds since Jan 1, 1970) 5const fromTimestamp = new Date(1704067200000); 6 7// From string (ISO 8601 recommended) 8const fromString = new Date('2024-01-01T12:00:00Z'); 9const fromDateString = new Date('2024-01-01'); 10 11// From components (months are 0-indexed!) 12const fromComponents = new Date(2024, 0, 15, 10, 30, 0); 13// January 15, 2024, 10:30:00 14 15// UTC date 16const utcDate = new Date(Date.UTC(2024, 0, 15, 10, 30, 0)); 17 18// Invalid date 19const invalid = new Date('not a date'); 20console.log(isNaN(invalid.getTime())); // true

Getting Date Components#

1const date = new Date('2024-06-15T14:30:45.123Z'); 2 3// Local time components 4date.getFullYear(); // 2024 5date.getMonth(); // 5 (June - 0-indexed) 6date.getDate(); // 15 7date.getDay(); // 6 (Saturday - 0=Sunday) 8date.getHours(); // Varies by timezone 9date.getMinutes(); // 30 10date.getSeconds(); // 45 11date.getMilliseconds(); // 123 12 13// UTC components 14date.getUTCFullYear(); // 2024 15date.getUTCMonth(); // 5 16date.getUTCDate(); // 15 17date.getUTCHours(); // 14 18date.getUTCMinutes(); // 30 19 20// Timestamp 21date.getTime(); // Milliseconds since epoch 22Date.now(); // Current timestamp 23 24// Timezone offset (minutes) 25date.getTimezoneOffset(); // e.g., -300 for EST

Setting Date Components#

1const date = new Date(); 2 3// Set individual components 4date.setFullYear(2025); 5date.setMonth(11); // December (0-indexed) 6date.setDate(25); 7date.setHours(12); 8date.setMinutes(0); 9date.setSeconds(0); 10date.setMilliseconds(0); 11 12// Set from timestamp 13date.setTime(1704067200000); 14 15// Chaining (returns timestamp, not Date) 16const timestamp = new Date() 17 .setFullYear(2025); 18// timestamp is a number, not Date! 19 20// Method returns new timestamp 21const newTimestamp = date.setMonth(5);

Formatting Dates#

1const date = new Date('2024-06-15T14:30:00'); 2 3// Built-in string methods 4date.toString(); 5// "Sat Jun 15 2024 14:30:00 GMT-0400 (Eastern Daylight Time)" 6 7date.toDateString(); // "Sat Jun 15 2024" 8date.toTimeString(); // "14:30:00 GMT-0400 (EDT)" 9date.toISOString(); // "2024-06-15T18:30:00.000Z" 10date.toUTCString(); // "Sat, 15 Jun 2024 18:30:00 GMT" 11date.toLocaleDateString(); // "6/15/2024" (locale-dependent) 12date.toLocaleTimeString(); // "2:30:00 PM" (locale-dependent) 13date.toLocaleString(); // "6/15/2024, 2:30:00 PM" 14 15// Intl.DateTimeFormat for more control 16const formatter = new Intl.DateTimeFormat('en-US', { 17 weekday: 'long', 18 year: 'numeric', 19 month: 'long', 20 day: 'numeric' 21}); 22 23formatter.format(date); // "Saturday, June 15, 2024" 24 25// Various formats 26new Intl.DateTimeFormat('en-US', { 27 dateStyle: 'full' 28}).format(date); 29// "Saturday, June 15, 2024" 30 31new Intl.DateTimeFormat('en-US', { 32 dateStyle: 'long', 33 timeStyle: 'short' 34}).format(date); 35// "June 15, 2024 at 2:30 PM"

Custom Formatting#

1function formatDate(date, format) { 2 const pad = (n) => String(n).padStart(2, '0'); 3 4 const replacements = { 5 'YYYY': date.getFullYear(), 6 'MM': pad(date.getMonth() + 1), 7 'DD': pad(date.getDate()), 8 'HH': pad(date.getHours()), 9 'mm': pad(date.getMinutes()), 10 'ss': pad(date.getSeconds()), 11 'M': date.getMonth() + 1, 12 'D': date.getDate(), 13 'H': date.getHours(), 14 }; 15 16 return format.replace( 17 /YYYY|MM|DD|HH|mm|ss|M|D|H/g, 18 match => replacements[match] 19 ); 20} 21 22formatDate(new Date(), 'YYYY-MM-DD'); // "2024-06-15" 23formatDate(new Date(), 'MM/DD/YYYY'); // "06/15/2024" 24formatDate(new Date(), 'YYYY-MM-DD HH:mm'); // "2024-06-15 14:30" 25 26// Relative time formatting 27const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' }); 28 29rtf.format(-1, 'day'); // "yesterday" 30rtf.format(1, 'day'); // "tomorrow" 31rtf.format(-2, 'hour'); // "2 hours ago" 32rtf.format(3, 'month'); // "in 3 months"

Date Arithmetic#

1const date = new Date('2024-06-15'); 2 3// Add/subtract days 4function addDays(date, days) { 5 const result = new Date(date); 6 result.setDate(result.getDate() + days); 7 return result; 8} 9 10addDays(date, 7); // June 22, 2024 11addDays(date, -30); // May 16, 2024 12 13// Add months (handles edge cases) 14function addMonths(date, months) { 15 const result = new Date(date); 16 const day = result.getDate(); 17 result.setMonth(result.getMonth() + months); 18 19 // Handle month overflow (e.g., Jan 31 + 1 month) 20 if (result.getDate() !== day) { 21 result.setDate(0); // Last day of previous month 22 } 23 24 return result; 25} 26 27addMonths(new Date('2024-01-31'), 1); // Feb 29, 2024 (leap year) 28 29// Add years 30function addYears(date, years) { 31 const result = new Date(date); 32 result.setFullYear(result.getFullYear() + years); 33 return result; 34} 35 36// Difference between dates 37function daysBetween(date1, date2) { 38 const MS_PER_DAY = 1000 * 60 * 60 * 24; 39 const utc1 = Date.UTC(date1.getFullYear(), date1.getMonth(), date1.getDate()); 40 const utc2 = Date.UTC(date2.getFullYear(), date2.getMonth(), date2.getDate()); 41 return Math.floor((utc2 - utc1) / MS_PER_DAY); 42}

Comparing Dates#

1const date1 = new Date('2024-01-15'); 2const date2 = new Date('2024-06-20'); 3 4// Compare timestamps 5date1.getTime() < date2.getTime(); // true 6date1 < date2; // true (implicit conversion) 7 8// Check equality 9date1.getTime() === date2.getTime(); // false 10// Don't use: date1 === date2 (different objects) 11 12// Same day check 13function isSameDay(d1, d2) { 14 return ( 15 d1.getFullYear() === d2.getFullYear() && 16 d1.getMonth() === d2.getMonth() && 17 d1.getDate() === d2.getDate() 18 ); 19} 20 21// Is before/after 22function isBefore(date1, date2) { 23 return date1.getTime() < date2.getTime(); 24} 25 26function isAfter(date1, date2) { 27 return date1.getTime() > date2.getTime(); 28} 29 30// Is between 31function isBetween(date, start, end) { 32 const time = date.getTime(); 33 return time >= start.getTime() && time <= end.getTime(); 34}

Start/End of Period#

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, 0); 27 result.setHours(23, 59, 59, 999); 28 return result; 29} 30 31// Start of week (Sunday) 32function startOfWeek(date) { 33 const result = new Date(date); 34 const day = result.getDay(); 35 result.setDate(result.getDate() - day); 36 result.setHours(0, 0, 0, 0); 37 return result; 38}

Parsing Dates#

1// ISO 8601 (recommended) 2new Date('2024-06-15T14:30:00Z'); // UTC 3new Date('2024-06-15T14:30:00-04:00'); // With offset 4new Date('2024-06-15T14:30:00'); // Local time 5 6// Date.parse returns timestamp 7Date.parse('2024-06-15'); // Timestamp 8 9// Custom parsing 10function parseDate(str, format) { 11 const formats = { 12 'YYYY-MM-DD': /^(\d{4})-(\d{2})-(\d{2})$/, 13 'MM/DD/YYYY': /^(\d{2})\/(\d{2})\/(\d{4})$/, 14 'DD.MM.YYYY': /^(\d{2})\.(\d{2})\.(\d{4})$/, 15 }; 16 17 const regex = formats[format]; 18 if (!regex) throw new Error('Unknown format'); 19 20 const match = str.match(regex); 21 if (!match) throw new Error('Invalid date string'); 22 23 if (format === 'YYYY-MM-DD') { 24 return new Date(+match[1], +match[2] - 1, +match[3]); 25 } 26 if (format === 'MM/DD/YYYY') { 27 return new Date(+match[3], +match[1] - 1, +match[2]); 28 } 29 if (format === 'DD.MM.YYYY') { 30 return new Date(+match[3], +match[2] - 1, +match[1]); 31 } 32} 33 34parseDate('15.06.2024', 'DD.MM.YYYY');

Timezone Handling#

1// Get timezone name 2Intl.DateTimeFormat().resolvedOptions().timeZone; 3// e.g., "America/New_York" 4 5// Format in specific timezone 6function formatInTimezone(date, timezone, options = {}) { 7 return new Intl.DateTimeFormat('en-US', { 8 ...options, 9 timeZone: timezone 10 }).format(date); 11} 12 13formatInTimezone(new Date(), 'America/New_York', { 14 dateStyle: 'full', 15 timeStyle: 'long' 16}); 17 18formatInTimezone(new Date(), 'Europe/London', { 19 hour: '2-digit', 20 minute: '2-digit' 21}); 22 23// Convert between timezones (display only) 24const date = new Date(); 25const options = { 26 timeZone: 'Asia/Tokyo', 27 year: 'numeric', 28 month: '2-digit', 29 day: '2-digit', 30 hour: '2-digit', 31 minute: '2-digit' 32}; 33new Intl.DateTimeFormat('ja-JP', options).format(date);

Best Practices#

Creation: ✓ Use ISO 8601 strings ✓ Use Date.UTC for UTC dates ✓ Validate parsed dates ✓ Remember months are 0-indexed Formatting: ✓ Use Intl.DateTimeFormat ✓ Store dates in UTC ✓ Display in user's timezone ✓ Use ISO for APIs Manipulation: ✓ Create new Date objects ✓ Handle month overflow ✓ Use UTC for calculations ✓ Consider timezone differences Avoid: ✗ Parsing ambiguous formats ✗ Mutating date objects ✗ Ignoring timezones ✗ Using deprecated methods

Conclusion#

JavaScript's Date object has quirks (0-indexed months, mutable methods) but is powerful when used correctly. Use ISO 8601 strings for parsing, Intl.DateTimeFormat for locale-aware formatting, and always consider timezones when storing and displaying dates. For complex date manipulation, consider libraries like date-fns or Luxon, but the native Date API handles most common cases effectively.

Share this article

Help spread the word about Bootspring