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())); // trueGetting 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 ESTSetting 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.