JavaScript Essentials

Date & Time in JavaScript

45 min Lesson 29 of 60

Introduction to the Date Object

Working with dates and times is one of the most common tasks in web development. Whether you are building a booking system, displaying timestamps on a blog, or calculating deadlines, you need to understand how JavaScript handles dates. JavaScript provides the built-in Date object for creating, manipulating, and formatting dates and times. In this lesson, you will master every aspect of working with dates -- from creating simple date instances to building real-world utilities like clocks, age calculators, and relative time displays.

The Date object in JavaScript represents a single moment in time. Internally, it stores the number of milliseconds that have elapsed since January 1, 1970, 00:00:00 UTC, which is known as the Unix epoch or POSIX time. This numeric representation makes it possible to perform arithmetic on dates, compare them, and convert between different formats and timezones.

Creating Date Objects

There are four main ways to create a Date object in JavaScript. Each method serves a different use case, and understanding when to use each one is essential for writing clean, predictable code.

1. Current Date and Time

The simplest way to create a Date object is with no arguments. This gives you the current date and time at the moment the code runs.

Example: Creating the Current Date

const now = new Date();
console.log(now);
// Output: something like "Sat Feb 07 2026 14:30:00 GMT+0300"

// The exact output depends on your timezone and when you run the code
console.log(typeof now); // "object"

2. From a Timestamp (Milliseconds)

You can create a Date from a numeric timestamp representing milliseconds since the Unix epoch. This is commonly used when working with APIs or databases that store dates as numbers.

Example: Creating a Date from a Timestamp

// January 1, 2025, 00:00:00 UTC
const fromTimestamp = new Date(1735689600000);
console.log(fromTimestamp);

// The Unix epoch itself (timestamp 0)
const epoch = new Date(0);
console.log(epoch); // Thu Jan 01 1970 ...

// Negative timestamps go before the epoch
const beforeEpoch = new Date(-86400000); // One day before epoch
console.log(beforeEpoch); // Wed Dec 31 1969 ...

3. From a Date String

You can pass a date string to the Date constructor. JavaScript will attempt to parse it. However, date string parsing can be inconsistent across browsers, so you should use standardized formats.

Example: Creating a Date from a String

// ISO 8601 format (recommended -- most reliable across browsers)
const isoDate = new Date('2025-06-15T10:30:00Z');
console.log(isoDate);

// Date-only string (interpreted as UTC)
const dateOnly = new Date('2025-06-15');
console.log(dateOnly);

// Other formats (less reliable -- avoid in production)
const informal = new Date('June 15, 2025');
console.log(informal);

const slashFormat = new Date('06/15/2025');
console.log(slashFormat);
Warning: Date string parsing is one of the most inconsistent areas in JavaScript. The string '2025-06-15' is treated as UTC midnight, while '2025/06/15' is treated as local midnight in some browsers. Always use ISO 8601 format (YYYY-MM-DDTHH:mm:ssZ) for the most predictable results across all environments.

4. From Individual Components

The most explicit way to create a Date is by passing individual year, month, day, hour, minute, second, and millisecond values. This gives you full control and avoids parsing ambiguities.

Example: Creating a Date from Components

// new Date(year, monthIndex, day, hours, minutes, seconds, milliseconds)
// IMPORTANT: monthIndex is 0-based (0 = January, 11 = December)

const christmas = new Date(2025, 11, 25); // December 25, 2025
console.log(christmas);

const specificTime = new Date(2025, 5, 15, 14, 30, 0);
// June 15, 2025 at 2:30:00 PM (local time)
console.log(specificTime);

// Only year and month are required; others default to 0 or 1
const monthStart = new Date(2025, 0); // January 1, 2025
console.log(monthStart);

// Two-digit years are mapped to 1900s
const oldDate = new Date(99, 0, 1); // January 1, 1999 (NOT 0099)
console.log(oldDate);
Note: The month parameter is zero-indexed, meaning January is 0 and December is 11. This is one of the most common sources of bugs when working with dates in JavaScript. Always remember to subtract 1 when setting the month and add 1 when displaying it.

Getting Date Components (Getter Methods)

Once you have a Date object, you can extract individual components using getter methods. Each getter returns the value in local time unless you use the UTC variant.

Example: Extracting Date Components

const date = new Date(2025, 5, 15, 14, 30, 45, 500);
// June 15, 2025, 2:30:45.500 PM

console.log(date.getFullYear());     // 2025
console.log(date.getMonth());        // 5 (June, 0-indexed)
console.log(date.getDate());         // 15 (day of month)
console.log(date.getDay());          // 0 (Sunday, 0=Sun, 6=Sat)
console.log(date.getHours());        // 14
console.log(date.getMinutes());      // 30
console.log(date.getSeconds());      // 45
console.log(date.getMilliseconds()); // 500
console.log(date.getTime());         // Timestamp in milliseconds
console.log(date.getTimezoneOffset()); // Minutes offset from UTC

Example: UTC Getter Methods

const date = new Date('2025-06-15T14:30:00Z');

// UTC methods return values in Coordinated Universal Time
console.log(date.getUTCFullYear());  // 2025
console.log(date.getUTCMonth());     // 5
console.log(date.getUTCDate());      // 15
console.log(date.getUTCDay());       // 0
console.log(date.getUTCHours());     // 14
console.log(date.getUTCMinutes());   // 30
console.log(date.getUTCSeconds());   // 0

// Compare local vs UTC
console.log('Local hours:', date.getHours());
console.log('UTC hours:', date.getUTCHours());
// These may differ based on your timezone

Setting Date Components (Setter Methods)

You can modify a Date object after creation using setter methods. Each setter changes the corresponding component in place and returns the new timestamp. JavaScript automatically handles overflow -- for example, setting the date to 32 in a 30-day month will roll over to the next month.

Example: Modifying Date Components

const date = new Date(2025, 0, 1); // January 1, 2025
console.log(date); // Wed Jan 01 2025

date.setFullYear(2026);
console.log(date); // Thu Jan 01 2026

date.setMonth(5); // Set to June (0-indexed)
console.log(date); // Mon Jun 01 2026

date.setDate(15);
console.log(date); // Mon Jun 15 2026

date.setHours(10);
date.setMinutes(30);
date.setSeconds(0);
console.log(date); // Mon Jun 15 2026 10:30:00

// Overflow is handled automatically
date.setDate(35); // June only has 30 days
console.log(date); // Rolls over to July 5, 2026

// You can also use negative values
date.setDate(0); // Day 0 = last day of previous month
console.log(date); // June 30, 2026
Pro Tip: The overflow behavior of setDate() is extremely useful. Setting the date to 0 gives you the last day of the previous month. This is one of the easiest ways to find how many days are in a given month: new Date(year, month + 1, 0).getDate() returns the number of days in that month.

Static Date Methods

The Date object provides static methods that you call on the Date class itself rather than on an instance.

Example: Date.now() and Date.parse()

// Date.now() returns the current timestamp in milliseconds
const timestamp = Date.now();
console.log(timestamp); // e.g., 1738900200000

// This is equivalent to (but faster than):
const sameTimestamp = new Date().getTime();

// Date.parse() parses a date string and returns a timestamp
const parsed = Date.parse('2025-06-15T10:30:00Z');
console.log(parsed); // 1750067400000

// Invalid date strings return NaN
const invalid = Date.parse('not a date');
console.log(invalid); // NaN

// Performance measurement using Date.now()
const start = Date.now();
// ... some operation ...
for (let i = 0; i < 1000000; i++) { /* work */ }
const end = Date.now();
console.log(`Operation took ${end - start} milliseconds`);

Timestamps and Unix Time

A timestamp is a numeric value representing a specific point in time. In JavaScript, timestamps are measured in milliseconds since the Unix epoch. Many other languages and systems use seconds since the epoch instead. Understanding this difference is critical when exchanging data between systems.

Example: Working with Timestamps

// JavaScript uses milliseconds
const jsTimestamp = Date.now();
console.log(jsTimestamp); // e.g., 1738900200000

// Unix timestamps (used by many APIs and databases) use seconds
const unixTimestamp = Math.floor(Date.now() / 1000);
console.log(unixTimestamp); // e.g., 1738900200

// Converting Unix timestamp to JavaScript Date
const fromUnix = new Date(unixTimestamp * 1000);
console.log(fromUnix);

// Converting JavaScript Date to Unix timestamp
const date = new Date('2025-01-01T00:00:00Z');
const toUnix = Math.floor(date.getTime() / 1000);
console.log(toUnix); // 1735689600

// Useful timestamp constants
const ONE_SECOND = 1000;
const ONE_MINUTE = 60 * 1000;
const ONE_HOUR = 60 * 60 * 1000;
const ONE_DAY = 24 * 60 * 60 * 1000;
const ONE_WEEK = 7 * 24 * 60 * 60 * 1000;

Formatting Dates

JavaScript provides several methods for converting dates to human-readable strings. The most flexible approach uses the Intl.DateTimeFormat API or the toLocaleString family of methods.

Built-in String Methods

Example: Basic Date Formatting Methods

const date = new Date(2025, 5, 15, 14, 30, 0);

// Full string representation
console.log(date.toString());
// "Sun Jun 15 2025 14:30:00 GMT+0300 (Arabian Standard Time)"

// Date portion only
console.log(date.toDateString());
// "Sun Jun 15 2025"

// Time portion only
console.log(date.toTimeString());
// "14:30:00 GMT+0300 (Arabian Standard Time)"

// ISO 8601 format (always UTC)
console.log(date.toISOString());
// "2025-06-15T11:30:00.000Z"

// UTC string
console.log(date.toUTCString());
// "Sun, 15 Jun 2025 11:30:00 GMT"

// JSON serialization uses ISO format
console.log(JSON.stringify({ created: date }));
// '{"created":"2025-06-15T11:30:00.000Z"}'

Locale-Aware Formatting

Example: toLocaleDateString and toLocaleTimeString

const date = new Date(2025, 5, 15, 14, 30, 0);

// Default locale formatting
console.log(date.toLocaleDateString());
// "6/15/2025" (US) or "15/6/2025" (UK) depending on browser locale

// Specifying locale
console.log(date.toLocaleDateString('en-US'));
// "6/15/2025"

console.log(date.toLocaleDateString('en-GB'));
// "15/06/2025"

console.log(date.toLocaleDateString('ar-SA'));
// Displays in Arabic numerals and format

// With options for custom formatting
console.log(date.toLocaleDateString('en-US', {
    weekday: 'long',
    year: 'numeric',
    month: 'long',
    day: 'numeric'
}));
// "Sunday, June 15, 2025"

// Time formatting with locale
console.log(date.toLocaleTimeString('en-US', {
    hour: '2-digit',
    minute: '2-digit',
    hour12: true
}));
// "02:30 PM"

console.log(date.toLocaleTimeString('en-GB', {
    hour: '2-digit',
    minute: '2-digit',
    hour12: false
}));
// "14:30"

Intl.DateTimeFormat

For more control and better performance when formatting many dates, use Intl.DateTimeFormat. This creates a reusable formatter object.

Example: Intl.DateTimeFormat

// Create a reusable formatter
const formatter = new Intl.DateTimeFormat('en-US', {
    weekday: 'long',
    year: 'numeric',
    month: 'long',
    day: 'numeric',
    hour: 'numeric',
    minute: '2-digit',
    timeZoneName: 'short'
});

const date = new Date(2025, 5, 15, 14, 30, 0);
console.log(formatter.format(date));
// "Sunday, June 15, 2025 at 2:30 PM GMT+3"

// Arabic formatter
const arFormatter = new Intl.DateTimeFormat('ar-EG', {
    weekday: 'long',
    year: 'numeric',
    month: 'long',
    day: 'numeric'
});
console.log(arFormatter.format(date));

// Format with specific timezone
const tokyoFormatter = new Intl.DateTimeFormat('en-US', {
    timeZone: 'Asia/Tokyo',
    hour: '2-digit',
    minute: '2-digit',
    timeZoneName: 'long'
});
console.log(tokyoFormatter.format(date));

// formatToParts gives you an array of components
const parts = formatter.formatToParts(date);
console.log(parts);
// [{type: "weekday", value: "Sunday"}, {type: "literal", value: ", "}, ...]

Date Arithmetic

JavaScript does not have built-in methods for adding or subtracting time from dates, but you can accomplish date arithmetic by manipulating timestamps or using getter and setter methods together.

Adding and Subtracting Time

Example: Adding Days, Months, and Years

// Adding days using setDate
function addDays(date, days) {
    const result = new Date(date);
    result.setDate(result.getDate() + days);
    return result;
}

const today = new Date(2025, 5, 15);
console.log(addDays(today, 10));  // June 25, 2025
console.log(addDays(today, 20));  // July 5, 2025 (automatic rollover)
console.log(addDays(today, -5));  // June 10, 2025 (subtract days)

// Adding months using setMonth
function addMonths(date, months) {
    const result = new Date(date);
    result.setMonth(result.getMonth() + months);
    return result;
}

console.log(addMonths(today, 3));  // September 15, 2025
console.log(addMonths(today, -2)); // April 15, 2025

// Adding years
function addYears(date, years) {
    const result = new Date(date);
    result.setFullYear(result.getFullYear() + years);
    return result;
}

console.log(addYears(today, 1)); // June 15, 2026

// Adding hours using timestamps
function addHours(date, hours) {
    return new Date(date.getTime() + hours * 60 * 60 * 1000);
}

const now = new Date();
console.log(addHours(now, 5)); // 5 hours from now

Calculating the Difference Between Two Dates

Example: Date Difference Calculations

function dateDifference(date1, date2) {
    const diffMs = Math.abs(date2.getTime() - date1.getTime());
    const diffSeconds = Math.floor(diffMs / 1000);
    const diffMinutes = Math.floor(diffMs / (1000 * 60));
    const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
    const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));

    return {
        milliseconds: diffMs,
        seconds: diffSeconds,
        minutes: diffMinutes,
        hours: diffHours,
        days: diffDays
    };
}

const start = new Date(2025, 0, 1);  // January 1, 2025
const end = new Date(2025, 11, 31);  // December 31, 2025

const diff = dateDifference(start, end);
console.log(`${diff.days} days`);      // 364 days
console.log(`${diff.hours} hours`);    // 8736 hours

// Days until a specific event
function daysUntil(targetDate) {
    const now = new Date();
    now.setHours(0, 0, 0, 0); // Reset to start of day
    const target = new Date(targetDate);
    target.setHours(0, 0, 0, 0);
    const diffMs = target.getTime() - now.getTime();
    return Math.ceil(diffMs / (1000 * 60 * 60 * 24));
}

console.log(daysUntil(new Date(2025, 11, 25)));
// Days until Christmas 2025

Comparing Dates

Comparing dates in JavaScript requires some care. You cannot use === to compare two Date objects because they are objects and comparison checks reference equality, not value equality. Instead, compare their timestamps.

Example: Comparing Dates Correctly

const date1 = new Date(2025, 5, 15);
const date2 = new Date(2025, 5, 15);
const date3 = new Date(2025, 5, 20);

// WRONG: comparing object references
console.log(date1 === date2); // false (different objects)
console.log(date1 == date2);  // false (different objects)

// CORRECT: comparing timestamps
console.log(date1.getTime() === date2.getTime()); // true
console.log(date1.getTime() < date3.getTime());   // true
console.log(date3.getTime() > date1.getTime());   // true

// You can use comparison operators directly on Date objects
// because they get coerced to numbers (timestamps)
console.log(date1 < date3);  // true
console.log(date3 > date1);  // true

// Helper functions for date comparison
function isSameDay(d1, d2) {
    return d1.getFullYear() === d2.getFullYear() &&
           d1.getMonth() === d2.getMonth() &&
           d1.getDate() === d2.getDate();
}

function isBefore(d1, d2) {
    return d1.getTime() < d2.getTime();
}

function isAfter(d1, d2) {
    return d1.getTime() > d2.getTime();
}

function isBetween(date, start, end) {
    const t = date.getTime();
    return t >= start.getTime() && t <= end.getTime();
}

console.log(isSameDay(date1, date2)); // true
console.log(isBefore(date1, date3));  // true

Timezone Considerations

Timezones are one of the trickiest aspects of working with dates. JavaScript Date objects are always stored in UTC internally, but most getter and setter methods return values in the user's local timezone. Understanding this duality is essential for building applications that work correctly across timezones.

Example: Working with Timezones

const date = new Date('2025-06-15T12:00:00Z'); // Noon UTC

// getTimezoneOffset returns the difference in MINUTES
// between UTC and local time (positive = behind UTC)
const offset = date.getTimezoneOffset();
console.log(`Timezone offset: ${offset} minutes`);
console.log(`Timezone offset: ${offset / 60} hours`);

// Display time in different timezones
const timezones = ['America/New_York', 'Europe/London', 'Asia/Tokyo', 'Asia/Riyadh'];

timezones.forEach(tz => {
    const formatted = date.toLocaleString('en-US', { timeZone: tz });
    console.log(`${tz}: ${formatted}`);
});

// Convert local time to a specific timezone
function getTimeInZone(date, timezone) {
    return new Intl.DateTimeFormat('en-US', {
        timeZone: timezone,
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit',
        hour12: false
    }).format(date);
}

console.log(getTimeInZone(new Date(), 'Asia/Riyadh'));
console.log(getTimeInZone(new Date(), 'America/New_York'));
Warning: Never store dates as locale-specific strings in your database. Always store them in UTC (using ISO 8601 format or Unix timestamps) and convert to the user's local timezone only when displaying. This prevents ambiguity and makes it possible to correctly compare and sort dates regardless of where your users are located.

Building a Live Digital Clock

Let us apply what we have learned to build a practical live clock that updates every second. This example demonstrates getting the current time, formatting it, and using setInterval for continuous updates.

Example: Digital Clock

function updateClock() {
    const now = new Date();

    const hours = String(now.getHours()).padStart(2, '0');
    const minutes = String(now.getMinutes()).padStart(2, '0');
    const seconds = String(now.getSeconds()).padStart(2, '0');

    const timeString = `${hours}:${minutes}:${seconds}`;

    const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday',
                  'Thursday', 'Friday', 'Saturday'];
    const months = ['January', 'February', 'March', 'April', 'May', 'June',
                    'July', 'August', 'September', 'October', 'November', 'December'];

    const dayName = days[now.getDay()];
    const monthName = months[now.getMonth()];
    const dateString = `${dayName}, ${monthName} ${now.getDate()}, ${now.getFullYear()}`;

    // If running in a browser:
    // document.getElementById('clock').textContent = timeString;
    // document.getElementById('date').textContent = dateString;

    console.log(`${dateString} -- ${timeString}`);
}

// Update every second
updateClock(); // Run immediately
setInterval(updateClock, 1000);

// To use in HTML:
// <div id="clock"></div>
// <div id="date"></div>

Building an Age Calculator

Calculating a person's exact age is more complex than simply subtracting years. You need to account for whether the birthday has occurred yet this year, and optionally compute months and days as well.

Example: Precise Age Calculator

function calculateAge(birthDate) {
    const today = new Date();
    const birth = new Date(birthDate);

    let years = today.getFullYear() - birth.getFullYear();
    let months = today.getMonth() - birth.getMonth();
    let days = today.getDate() - birth.getDate();

    // Adjust if the day has not occurred yet this month
    if (days < 0) {
        months--;
        // Get the number of days in the previous month
        const prevMonth = new Date(today.getFullYear(), today.getMonth(), 0);
        days += prevMonth.getDate();
    }

    // Adjust if the month has not occurred yet this year
    if (months < 0) {
        years--;
        months += 12;
    }

    return { years, months, days };
}

const age = calculateAge('1995-03-20');
console.log(`Age: ${age.years} years, ${age.months} months, ${age.days} days`);

// Days until next birthday
function daysUntilBirthday(birthDate) {
    const today = new Date();
    const birth = new Date(birthDate);

    let nextBirthday = new Date(
        today.getFullYear(),
        birth.getMonth(),
        birth.getDate()
    );

    // If the birthday has already passed this year, use next year
    if (nextBirthday < today) {
        nextBirthday.setFullYear(today.getFullYear() + 1);
    }

    const diffMs = nextBirthday.getTime() - today.getTime();
    return Math.ceil(diffMs / (1000 * 60 * 60 * 24));
}

console.log(`Days until birthday: ${daysUntilBirthday('1995-03-20')}`);

// Check if it is a leap year birthday
function isLeapYear(year) {
    return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
}

console.log(isLeapYear(2024)); // true
console.log(isLeapYear(2025)); // false

Relative Time ("3 Days Ago")

Modern applications often display times in a relative format like "5 minutes ago" or "in 3 days." You can build this using the Intl.RelativeTimeFormat API or a custom function.

Example: Relative Time Display

// Using Intl.RelativeTimeFormat
const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });

console.log(rtf.format(-1, 'day'));    // "yesterday"
console.log(rtf.format(1, 'day'));     // "tomorrow"
console.log(rtf.format(-3, 'day'));    // "3 days ago"
console.log(rtf.format(2, 'hour'));    // "in 2 hours"
console.log(rtf.format(-1, 'week'));   // "last week"

// Arabic relative time
const rtfAr = new Intl.RelativeTimeFormat('ar', { numeric: 'auto' });
console.log(rtfAr.format(-1, 'day'));  // Outputs Arabic for "yesterday"
console.log(rtfAr.format(-3, 'day')); // Outputs Arabic for "3 days ago"

// Custom function for automatic unit selection
function timeAgo(date) {
    const now = new Date();
    const diffMs = now.getTime() - new Date(date).getTime();
    const diffSeconds = Math.floor(diffMs / 1000);
    const diffMinutes = Math.floor(diffSeconds / 60);
    const diffHours = Math.floor(diffMinutes / 60);
    const diffDays = Math.floor(diffHours / 24);
    const diffWeeks = Math.floor(diffDays / 7);
    const diffMonths = Math.floor(diffDays / 30);
    const diffYears = Math.floor(diffDays / 365);

    const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });

    if (diffSeconds < 60) return rtf.format(-diffSeconds, 'second');
    if (diffMinutes < 60) return rtf.format(-diffMinutes, 'minute');
    if (diffHours < 24) return rtf.format(-diffHours, 'hour');
    if (diffDays < 7) return rtf.format(-diffDays, 'day');
    if (diffWeeks < 4) return rtf.format(-diffWeeks, 'week');
    if (diffMonths < 12) return rtf.format(-diffMonths, 'month');
    return rtf.format(-diffYears, 'year');
}

// Test with various dates
const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000);
console.log(timeAgo(fiveMinutesAgo)); // "5 minutes ago"

const twoDaysAgo = new Date(Date.now() - 2 * 24 * 60 * 60 * 1000);
console.log(timeAgo(twoDaysAgo)); // "2 days ago"

const threeMonthsAgo = new Date(Date.now() - 90 * 24 * 60 * 60 * 1000);
console.log(timeAgo(threeMonthsAgo)); // "3 months ago"

Practical Utilities

Here are some commonly needed date utility functions that bring together everything we have covered.

Example: Useful Date Utility Functions

// Get the number of days in a month
function getDaysInMonth(year, month) {
    return new Date(year, month + 1, 0).getDate();
}
console.log(getDaysInMonth(2025, 1)); // 28 (February 2025)
console.log(getDaysInMonth(2024, 1)); // 29 (February 2024, leap year)

// Get the first and last day of a month
function getMonthRange(year, month) {
    const firstDay = new Date(year, month, 1);
    const lastDay = new Date(year, month + 1, 0);
    return { firstDay, lastDay };
}
const june = getMonthRange(2025, 5);
console.log(june.firstDay); // June 1
console.log(june.lastDay);  // June 30

// Check if a date is valid
function isValidDate(dateString) {
    const date = new Date(dateString);
    return !isNaN(date.getTime());
}
console.log(isValidDate('2025-06-15')); // true
console.log(isValidDate('invalid'));     // false

// Format a date as YYYY-MM-DD
function formatDate(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    return `${year}-${month}-${day}`;
}
console.log(formatDate(new Date(2025, 5, 15))); // "2025-06-15"

// Get an array of dates between two dates
function getDateRange(startDate, endDate) {
    const dates = [];
    const current = new Date(startDate);
    const end = new Date(endDate);

    while (current <= end) {
        dates.push(new Date(current));
        current.setDate(current.getDate() + 1);
    }
    return dates;
}

const range = getDateRange('2025-06-01', '2025-06-07');
range.forEach(d => console.log(formatDate(d)));
// Prints June 1 through June 7
Note: While the built-in Date object is sufficient for many tasks, large-scale applications that need advanced timezone handling, calendar systems, or complex date manipulations may benefit from the newer Temporal API (currently a stage 3 TC39 proposal) or established libraries. For most use cases covered in this lesson, the native Date object works perfectly well.

Practice Exercise

Build a comprehensive date utility application that includes the following features: (1) A countdown timer that displays the days, hours, minutes, and seconds until a target date provided by the user. (2) An age calculator that accepts a birth date and displays the precise age in years, months, and days, along with the number of days until the next birthday. (3) A date formatter that takes a date input and displays it in at least five different formats including ISO, US format, European format, a long human-readable format, and a relative time format like "3 months ago." (4) A timezone converter that displays the current time in at least four different timezones simultaneously. Test each function with edge cases including leap years, month boundaries, year boundaries, and the transition between December 31 and January 1.