Back to Blog
JavaScriptDateTimeFormatting

JavaScript Date Handling Guide

Master JavaScript Date handling. From parsing to formatting to time zones and libraries.

B
Bootspring Team
Engineering
May 25, 2020
7 min read

Working with dates in JavaScript requires understanding 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(1609459200000); 6 7// From string (ISO 8601) 8const fromISO = new Date('2021-01-01T00:00:00.000Z'); 9 10// From string (various formats) 11const fromString1 = new Date('January 1, 2021'); 12const fromString2 = new Date('01/01/2021'); 13const fromString3 = new Date('2021-01-01'); 14 15// From components (month is 0-indexed!) 16const fromComponents = new Date(2021, 0, 1, 12, 30, 0); 17// Year, Month (0-11), Day, Hours, Minutes, Seconds, Milliseconds 18 19// UTC date 20const utcDate = new Date(Date.UTC(2021, 0, 1, 12, 0, 0));

Getting Date Components#

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

Setting Date Components#

1const date = new Date(); 2 3// Set individual components 4date.setFullYear(2022); 5date.setMonth(11); // December 6date.setDate(25); 7date.setHours(12); 8date.setMinutes(0); 9date.setSeconds(0); 10date.setMilliseconds(0); 11 12// Set UTC components 13date.setUTCFullYear(2022); 14date.setUTCMonth(11); 15date.setUTCDate(25); 16 17// Set timestamp 18date.setTime(1640433600000); 19 20// Chaining (returns timestamp) 21new Date().setFullYear(2022); // Returns timestamp, not Date 22 23// Create modified copy 24function addDays(date, days) { 25 const result = new Date(date); 26 result.setDate(result.getDate() + days); 27 return result; 28}

Date Formatting#

1const date = new Date('2021-06-15T14:30:00'); 2 3// Built-in methods 4date.toString(); // "Tue Jun 15 2021 14:30:00 GMT-0400" 5date.toDateString(); // "Tue Jun 15 2021" 6date.toTimeString(); // "14:30:00 GMT-0400" 7date.toISOString(); // "2021-06-15T18:30:00.000Z" 8date.toUTCString(); // "Tue, 15 Jun 2021 18:30:00 GMT" 9date.toLocaleDateString(); // "6/15/2021" (varies by locale) 10date.toLocaleTimeString(); // "2:30:00 PM" (varies by locale) 11date.toLocaleString(); // "6/15/2021, 2:30:00 PM" 12 13// Intl.DateTimeFormat 14const formatter = new Intl.DateTimeFormat('en-US', { 15 year: 'numeric', 16 month: 'long', 17 day: 'numeric', 18 weekday: 'long', 19}); 20formatter.format(date); // "Tuesday, June 15, 2021" 21 22// More options 23const timeFormatter = new Intl.DateTimeFormat('en-US', { 24 hour: 'numeric', 25 minute: '2-digit', 26 second: '2-digit', 27 hour12: true, 28 timeZoneName: 'short', 29}); 30timeFormatter.format(date); // "2:30:00 PM EDT" 31 32// Relative time 33const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' }); 34rtf.format(-1, 'day'); // "yesterday" 35rtf.format(2, 'week'); // "in 2 weeks" 36rtf.format(-3, 'month'); // "3 months ago"

Custom Formatting#

1function formatDate(date, format) { 2 const pad = (n) => String(n).padStart(2, '0'); 3 4 const tokens = { 5 YYYY: date.getFullYear(), 6 YY: String(date.getFullYear()).slice(-2), 7 MM: pad(date.getMonth() + 1), 8 M: date.getMonth() + 1, 9 DD: pad(date.getDate()), 10 D: date.getDate(), 11 HH: pad(date.getHours()), 12 H: date.getHours(), 13 hh: pad(date.getHours() % 12 || 12), 14 h: date.getHours() % 12 || 12, 15 mm: pad(date.getMinutes()), 16 m: date.getMinutes(), 17 ss: pad(date.getSeconds()), 18 s: date.getSeconds(), 19 A: date.getHours() >= 12 ? 'PM' : 'AM', 20 a: date.getHours() >= 12 ? 'pm' : 'am', 21 }; 22 23 return format.replace(/YYYY|YY|MM|M|DD|D|HH|H|hh|h|mm|m|ss|s|A|a/g, 24 match => tokens[match] 25 ); 26} 27 28formatDate(new Date(), 'YYYY-MM-DD'); // "2021-06-15" 29formatDate(new Date(), 'MM/DD/YYYY'); // "06/15/2021" 30formatDate(new Date(), 'HH:mm:ss'); // "14:30:00" 31formatDate(new Date(), 'h:mm A'); // "2:30 PM" 32formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss'); // "2021-06-15 14:30:00"

Date Arithmetic#

1// Add/subtract time 2function addTime(date, value, unit) { 3 const result = new Date(date); 4 5 switch (unit) { 6 case 'years': 7 result.setFullYear(result.getFullYear() + value); 8 break; 9 case 'months': 10 result.setMonth(result.getMonth() + value); 11 break; 12 case 'weeks': 13 result.setDate(result.getDate() + value * 7); 14 break; 15 case 'days': 16 result.setDate(result.getDate() + value); 17 break; 18 case 'hours': 19 result.setHours(result.getHours() + value); 20 break; 21 case 'minutes': 22 result.setMinutes(result.getMinutes() + value); 23 break; 24 case 'seconds': 25 result.setSeconds(result.getSeconds() + value); 26 break; 27 } 28 29 return result; 30} 31 32// Difference between dates 33function dateDiff(date1, date2, unit = 'days') { 34 const diff = date2.getTime() - date1.getTime(); 35 36 switch (unit) { 37 case 'seconds': 38 return Math.floor(diff / 1000); 39 case 'minutes': 40 return Math.floor(diff / (1000 * 60)); 41 case 'hours': 42 return Math.floor(diff / (1000 * 60 * 60)); 43 case 'days': 44 return Math.floor(diff / (1000 * 60 * 60 * 24)); 45 case 'weeks': 46 return Math.floor(diff / (1000 * 60 * 60 * 24 * 7)); 47 } 48} 49 50const today = new Date(); 51const nextWeek = addTime(today, 1, 'weeks'); 52const daysDiff = dateDiff(today, nextWeek, 'days'); // 7

Date Comparison#

1const date1 = new Date('2021-01-01'); 2const date2 = new Date('2021-06-15'); 3 4// Compare timestamps 5date1.getTime() < date2.getTime(); // true 6date1.getTime() === date2.getTime(); // false 7 8// Compare dates only (ignore time) 9function isSameDay(d1, d2) { 10 return ( 11 d1.getFullYear() === d2.getFullYear() && 12 d1.getMonth() === d2.getMonth() && 13 d1.getDate() === d2.getDate() 14 ); 15} 16 17// Check if date is between 18function isBetween(date, start, end) { 19 const time = date.getTime(); 20 return time >= start.getTime() && time <= end.getTime(); 21} 22 23// Check if date is in past/future 24function isPast(date) { 25 return date.getTime() < Date.now(); 26} 27 28function isFuture(date) { 29 return date.getTime() > Date.now(); 30} 31 32// Check if today 33function isToday(date) { 34 return isSameDay(date, new Date()); 35}

Working with Time Zones#

1// Get timezone name 2Intl.DateTimeFormat().resolvedOptions().timeZone; 3// e.g., "America/New_York" 4 5// Format in specific timezone 6function formatInTimezone(date, timezone) { 7 return new Intl.DateTimeFormat('en-US', { 8 timeZone: timezone, 9 year: 'numeric', 10 month: '2-digit', 11 day: '2-digit', 12 hour: '2-digit', 13 minute: '2-digit', 14 second: '2-digit', 15 hour12: false, 16 }).format(date); 17} 18 19formatInTimezone(new Date(), 'America/New_York'); 20formatInTimezone(new Date(), 'Europe/London'); 21formatInTimezone(new Date(), 'Asia/Tokyo'); 22 23// Parse date in specific timezone 24function parseDateInTimezone(dateStr, timezone) { 25 const date = new Date(dateStr); 26 const utcDate = new Date(date.toLocaleString('en-US', { timeZone: 'UTC' })); 27 const tzDate = new Date(date.toLocaleString('en-US', { timeZone: timezone })); 28 const offset = utcDate.getTime() - tzDate.getTime(); 29 return new Date(date.getTime() + offset); 30}

Common Utilities#

1// Start/end of day 2function startOfDay(date) { 3 const result = new Date(date); 4 result.setHours(0, 0, 0, 0); 5 return result; 6} 7 8function endOfDay(date) { 9 const result = new Date(date); 10 result.setHours(23, 59, 59, 999); 11 return result; 12} 13 14// Start/end of month 15function startOfMonth(date) { 16 return new Date(date.getFullYear(), date.getMonth(), 1); 17} 18 19function endOfMonth(date) { 20 return new Date(date.getFullYear(), date.getMonth() + 1, 0, 23, 59, 59, 999); 21} 22 23// Days in month 24function daysInMonth(year, month) { 25 return new Date(year, month + 1, 0).getDate(); 26} 27 28// Is leap year 29function isLeapYear(year) { 30 return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; 31} 32 33// Week number 34function getWeekNumber(date) { 35 const d = new Date(date); 36 d.setHours(0, 0, 0, 0); 37 d.setDate(d.getDate() + 4 - (d.getDay() || 7)); 38 const yearStart = new Date(d.getFullYear(), 0, 1); 39 return Math.ceil((((d - yearStart) / 86400000) + 1) / 7); 40}

Libraries#

1// date-fns (recommended) 2import { format, addDays, differenceInDays, isAfter } from 'date-fns'; 3 4format(new Date(), 'yyyy-MM-dd'); 5addDays(new Date(), 7); 6differenceInDays(date1, date2); 7isAfter(date1, date2); 8 9// Day.js (lightweight) 10import dayjs from 'dayjs'; 11 12dayjs().format('YYYY-MM-DD'); 13dayjs().add(7, 'day'); 14dayjs('2021-01-01').diff(dayjs('2021-06-15'), 'day'); 15 16// Luxon (full-featured) 17import { DateTime } from 'luxon'; 18 19DateTime.now().toISO(); 20DateTime.now().plus({ days: 7 }); 21DateTime.fromISO('2021-01-01').diff(DateTime.fromISO('2021-06-15'), 'days');

Best Practices#

Parsing: ✓ Use ISO 8601 format for parsing ✓ Be explicit about timezones ✓ Validate parsed dates ✓ Handle invalid dates gracefully Storage: ✓ Store as ISO 8601 strings or timestamps ✓ Store in UTC ✓ Convert to local time for display ✓ Use consistent formats Display: ✓ Use Intl.DateTimeFormat for localization ✓ Consider user's timezone ✓ Use relative time when appropriate ✓ Be consistent across the app Avoid: ✗ Parsing ambiguous date strings ✗ Mutating Date objects ✗ Ignoring timezones ✗ Manual string formatting for locales

Conclusion#

JavaScript's Date handling has quirks like 0-indexed months and timezone complexities. Use ISO 8601 format for parsing, Intl APIs for formatting, and consider libraries like date-fns for complex operations. Always be explicit about timezones and store dates in UTC.

Share this article

Help spread the word about Bootspring