Docs
README
15.2 Date Formatting & Calculations
Overview
Working with dates often involves formatting them for display and performing calculations like finding differences or adding/subtracting time. This section covers formatting options, date arithmetic, and common date manipulation patterns.
Date Formatting
Built-in Formatting Methods
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Built-in Date Formatting ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā Method ā Example Output ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā toString() ā "Wed Dec 25 2024 10:30:00 GMT-0500" ā
ā toDateString() ā "Wed Dec 25 2024" ā
ā toTimeString() ā "10:30:00 GMT-0500" ā
ā toISOString() ā "2024-12-25T15:30:00.000Z" ā
ā toUTCString() ā "Wed, 25 Dec 2024 15:30:00 GMT" ā
ā toLocaleString() ā "12/25/2024, 10:30:00 AM" ā
ā toLocaleDateString() ā "12/25/2024" ā
ā toLocaleTimeString() ā "10:30:00 AM" ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Intl.DateTimeFormat
The Intl.DateTimeFormat object provides powerful locale-aware date formatting:
const date = new Date('2024-12-25T10:30:00');
// Basic usage
new Intl.DateTimeFormat('en-US').format(date); // "12/25/2024"
new Intl.DateTimeFormat('de-DE').format(date); // "25.12.2024"
new Intl.DateTimeFormat('ja-JP').format(date); // "2024/12/25"
// With options
const formatter = new Intl.DateTimeFormat('en-US', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
});
formatter.format(date); // "Wednesday, December 25, 2024"
Format Options
| Option | Values |
|---|---|
weekday | 'narrow', 'short', 'long' |
year | 'numeric', '2-digit' |
month | 'numeric', '2-digit', 'narrow', 'short', 'long' |
day | 'numeric', '2-digit' |
hour | 'numeric', '2-digit' |
minute | 'numeric', '2-digit' |
second | 'numeric', '2-digit' |
hour12 | true, false |
timeZone | 'UTC', 'America/New_York', etc. |
timeZoneName | 'short', 'long' |
const date = new Date('2024-12-25T10:30:00');
// Different weekday formats
const options = { weekday: 'narrow' }; // "W"
const options = { weekday: 'short' }; // "Wed"
const options = { weekday: 'long' }; // "Wednesday"
// Different month formats
const options = { month: 'numeric' }; // "12"
const options = { month: '2-digit' }; // "12"
const options = { month: 'narrow' }; // "D"
const options = { month: 'short' }; // "Dec"
const options = { month: 'long' }; // "December"
// Time formatting
const options = {
hour: '2-digit',
minute: '2-digit',
hour12: true,
}; // "10:30 AM"
const options = {
hour: '2-digit',
minute: '2-digit',
hour12: false,
}; // "10:30"
Custom Format Function
function formatDate(date, format) {
const map = {
YYYY: date.getFullYear(),
YY: String(date.getFullYear()).slice(-2),
MM: String(date.getMonth() + 1).padStart(2, '0'),
M: date.getMonth() + 1,
DD: String(date.getDate()).padStart(2, '0'),
D: date.getDate(),
HH: String(date.getHours()).padStart(2, '0'),
H: date.getHours(),
mm: String(date.getMinutes()).padStart(2, '0'),
m: date.getMinutes(),
ss: String(date.getSeconds()).padStart(2, '0'),
s: date.getSeconds(),
};
return format.replace(
/YYYY|YY|MM|M|DD|D|HH|H|mm|m|ss|s/g,
(match) => map[match]
);
}
formatDate(new Date(), 'YYYY-MM-DD'); // "2024-12-25"
formatDate(new Date(), 'DD/MM/YYYY'); // "25/12/2024"
formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss'); // "2024-12-25 10:30:00"
Date Arithmetic
Adding and Subtracting Time
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Date Arithmetic ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā ā
ā Using setX() methods: ā
ā āāāāāāāāāāāāāāāāāāāāā ā
ā date.setDate(date.getDate() + 7) // Add 7 days ā
ā date.setMonth(date.getMonth() - 1) // Subtract 1 month ā
ā date.setFullYear(date.getFullYear() + 1) // Add 1 year ā
ā ā
ā Using milliseconds: ā
ā āāāāāāāāāāāāāāāāāāā ā
ā new Date(date.getTime() + (days * 24 * 60 * 60 * 1000)) ā
ā ā
ā Time units in milliseconds: ā
ā āāāāāāāāāāāāāāāāāāāāāāāāā ā
ā 1 second = 1,000 ms ā
ā 1 minute = 60,000 ms ā
ā 1 hour = 3,600,000 ms ā
ā 1 day = 86,400,000 ms ā
ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
// Add/subtract using setters
function addDays(date, days) {
const result = new Date(date);
result.setDate(result.getDate() + days);
return result;
}
function addMonths(date, months) {
const result = new Date(date);
result.setMonth(result.getMonth() + months);
return result;
}
function addYears(date, years) {
const result = new Date(date);
result.setFullYear(result.getFullYear() + years);
return result;
}
// Examples
const today = new Date('2024-12-25');
addDays(today, 7); // 2025-01-01
addDays(today, -7); // 2024-12-18
addMonths(today, 1); // 2025-01-25
addMonths(today, -6); // 2024-06-25
addYears(today, 1); // 2025-12-25
Time Constants
const MS_PER_SECOND = 1000;
const MS_PER_MINUTE = 60 * MS_PER_SECOND;
const MS_PER_HOUR = 60 * MS_PER_MINUTE;
const MS_PER_DAY = 24 * MS_PER_HOUR;
const MS_PER_WEEK = 7 * MS_PER_DAY;
// Add 2 hours using milliseconds
function addHours(date, hours) {
return new Date(date.getTime() + hours * MS_PER_HOUR);
}
// Add 30 minutes
function addMinutes(date, minutes) {
return new Date(date.getTime() + minutes * MS_PER_MINUTE);
}
Calculating Differences
Difference Between Dates
function dateDiff(date1, date2) {
const ms = Math.abs(date2 - date1);
return {
milliseconds: ms,
seconds: Math.floor(ms / 1000),
minutes: Math.floor(ms / (1000 * 60)),
hours: Math.floor(ms / (1000 * 60 * 60)),
days: Math.floor(ms / (1000 * 60 * 60 * 24)),
weeks: Math.floor(ms / (1000 * 60 * 60 * 24 * 7)),
};
}
const start = new Date('2024-01-01');
const end = new Date('2024-12-31');
const diff = dateDiff(start, end);
// { days: 365, weeks: 52, hours: 8760, ... }
Difference in Specific Units
function diffInDays(date1, date2) {
const oneDay = 24 * 60 * 60 * 1000;
return Math.round((date2 - date1) / oneDay);
}
function diffInMonths(date1, date2) {
let months = (date2.getFullYear() - date1.getFullYear()) * 12;
months += date2.getMonth() - date1.getMonth();
return months;
}
function diffInYears(date1, date2) {
return date2.getFullYear() - date1.getFullYear();
}
Relative Time
Relative Time Formatter
function getRelativeTime(date, baseDate = new Date()) {
const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
const diff = date - baseDate;
const absDiff = Math.abs(diff);
const seconds = absDiff / 1000;
const minutes = seconds / 60;
const hours = minutes / 60;
const days = hours / 24;
const weeks = days / 7;
const months = days / 30;
const years = days / 365;
const sign = diff < 0 ? -1 : 1;
if (seconds < 60) {
return rtf.format(Math.round(seconds) * sign, 'second');
} else if (minutes < 60) {
return rtf.format(Math.round(minutes) * sign, 'minute');
} else if (hours < 24) {
return rtf.format(Math.round(hours) * sign, 'hour');
} else if (days < 7) {
return rtf.format(Math.round(days) * sign, 'day');
} else if (weeks < 4) {
return rtf.format(Math.round(weeks) * sign, 'week');
} else if (months < 12) {
return rtf.format(Math.round(months) * sign, 'month');
} else {
return rtf.format(Math.round(years) * sign, 'year');
}
}
getRelativeTime(new Date(Date.now() - 5000)); // "5 seconds ago"
getRelativeTime(new Date(Date.now() + 86400000)); // "tomorrow"
Simple Relative Time
function timeAgo(date) {
const seconds = Math.floor((new Date() - date) / 1000);
const intervals = {
year: 31536000,
month: 2592000,
week: 604800,
day: 86400,
hour: 3600,
minute: 60,
second: 1,
};
for (const [unit, secondsInUnit] of Object.entries(intervals)) {
const interval = Math.floor(seconds / secondsInUnit);
if (interval >= 1) {
return `${interval} ${unit}${interval === 1 ? '' : 's'} ago`;
}
}
return 'just now';
}
Working with Ranges
Date Range Generator
function* dateRange(start, end, step = 1) {
const current = new Date(start);
while (current <= end) {
yield new Date(current);
current.setDate(current.getDate() + step);
}
}
// Usage
const start = new Date('2024-01-01');
const end = new Date('2024-01-07');
for (const date of dateRange(start, end)) {
console.log(date.toDateString());
}
Get All Days in Month
function getDaysInMonth(year, month) {
const date = new Date(year, month, 1);
const days = [];
while (date.getMonth() === month) {
days.push(new Date(date));
date.setDate(date.getDate() + 1);
}
return days;
}
const december2024 = getDaysInMonth(2024, 11); // Array of 31 dates
Business Day Calculations
function isWeekend(date) {
const day = date.getDay();
return day === 0 || day === 6;
}
function addBusinessDays(date, days) {
const result = new Date(date);
let added = 0;
while (added < days) {
result.setDate(result.getDate() + 1);
if (!isWeekend(result)) {
added++;
}
}
return result;
}
function getBusinessDaysBetween(start, end) {
let count = 0;
const current = new Date(start);
while (current < end) {
current.setDate(current.getDate() + 1);
if (!isWeekend(current)) {
count++;
}
}
return count;
}
Common Calculations
Age Calculator
function calculateAge(birthDate) {
const today = new Date();
let age = today.getFullYear() - birthDate.getFullYear();
const monthDiff = today.getMonth() - birthDate.getMonth();
if (
monthDiff < 0 ||
(monthDiff === 0 && today.getDate() < birthDate.getDate())
) {
age--;
}
return age;
}
calculateAge(new Date('1990-05-15')); // Returns current age
Days Until/Since
function daysUntil(targetDate) {
const today = new Date();
today.setHours(0, 0, 0, 0);
const target = new Date(targetDate);
target.setHours(0, 0, 0, 0);
return Math.ceil((target - today) / (1000 * 60 * 60 * 24));
}
function daysSince(pastDate) {
return -daysUntil(pastDate);
}
daysUntil(new Date('2024-12-25')); // Days until Christmas
daysSince(new Date('2024-01-01')); // Days since New Year
Next Occurrence
function getNextWeekday(dayOfWeek) {
// dayOfWeek: 0 = Sunday, 1 = Monday, etc.
const today = new Date();
const currentDay = today.getDay();
const daysUntil = (dayOfWeek - currentDay + 7) % 7 || 7;
const next = new Date(today);
next.setDate(today.getDate() + daysUntil);
return next;
}
getNextWeekday(1); // Next Monday
getNextWeekday(5); // Next Friday
Calendar Helpers
Get Calendar Month Grid
function getCalendarMonth(year, month) {
const firstDay = new Date(year, month, 1);
const lastDay = new Date(year, month + 1, 0);
const calendar = [];
let week = [];
// Pad the beginning with nulls
for (let i = 0; i < firstDay.getDay(); i++) {
week.push(null);
}
// Add all days
for (let day = 1; day <= lastDay.getDate(); day++) {
week.push(day);
if (week.length === 7) {
calendar.push(week);
week = [];
}
}
// Pad the end with nulls
while (week.length > 0 && week.length < 7) {
week.push(null);
}
if (week.length) calendar.push(week);
return calendar;
}
// Returns 2D array for calendar display
// [[null, null, null, null, null, 1, 2], [3, 4, 5, 6, 7, 8, 9], ...]
Key Takeaways
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Date Formatting & Calculations ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā 1. Use Intl.DateTimeFormat for locale-aware formatting ā
ā 2. toISOString() for storage/APIs, toLocale* for display ā
ā 3. Date math: use setters (auto-rollover) or milliseconds ā
ā 4. Difference: subtract dates to get milliseconds ā
ā 5. Intl.RelativeTimeFormat for "2 days ago" style ā
ā 6. Always clone dates before modifying ā
ā 7. Consider business days for work-related calculations ā
ā 8. Month calculations need special care (varying days) ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā