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-4Setting 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'); // 7Date 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.