JavaScript Date: Working with Dates and Times in JS

JavaScript's Date object is the built-in way to work with dates, times, timestamps, and time zones. It is used for everything from showing a post's published time to scheduling reminders and measuring elapsed time.

Quick answer: Date is the built-in JavaScript object for representing a specific moment in time. You create one with new Date(), then read or change values with methods like getFullYear(), toISOString(), and getTime().

Difficulty: Beginner

You'll understand this better if you know: basic JavaScript variables, functions, and how objects store data and behavior.

1. What Is Date?

Date is JavaScript's standard object for representing points in time. Internally, a date value is stored as a number of milliseconds since the Unix epoch: midnight at the start of January 1, 1970, UTC.

That means a Date object is useful for both human-friendly calendar display and machine-friendly time calculations.

2. Why Date Matters

Nearly every application needs dates and times at some point. A shopping app may need delivery dates, a dashboard may show last-updated times, and a scheduling tool may compare two timestamps.

JavaScript's Date matters because it is available everywhere JavaScript runs, including browsers and Node.js. You do not need a library for basic date storage, comparison, or formatting.

At the same time, Date is also one of the most misunderstood built-in objects because time zones, parsing rules, and locale formatting can produce unexpected results. Learning the built-in behavior helps you avoid subtle bugs.

3. Basic Syntax or Core Idea

The most common way to create a date is with new Date(). You can create the current moment, a specific timestamp, or a date from a string.

Create the current date and time

This creates a Date for the exact moment the code runs.

const now = new Date();

Create a date from year, month, and day

The month number is zero-based, so 0 means January and 11 means December.

const independenceDay = new Date(2026, 6, 4);

Create a date from a timestamp

A timestamp is the number of milliseconds since the Unix epoch.

const fromTimestamp = new Date(1719830400000);

Once you have a date, you can read parts of it with methods such as getFullYear(), getMonth(), getDate(), and getHours().

4. Step-by-Step Examples

Example 1: Get today's date and format it

This example creates a Date object for the current moment and prints a simple local date string.

const today = new Date();

console.log(today.toDateString());

This is useful for quick display, though it is not ideal for custom formatting.

Example 2: Read the individual parts of a date

Sometimes you need the year, month, and day separately.

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

const year = date.getFullYear();
const month = date.getMonth();
const day = date.getDate();

console.log(year, month, day);

Remember that getMonth() returns a zero-based month, so January is 0.

Example 3: Compare two dates

You can compare timestamps directly by converting each date with getTime().

const start = new Date(2025, 0, 1);
const end = new Date(2025, 0, 31);

if (end.getTime() > start.getTime()) {
  console.log("End is after start");
}

Because timestamps are just numbers, date comparisons are simple and reliable.

Example 4: Format a date for display

The toLocaleDateString() method uses the user's locale to format a readable date.

const eventDate = new Date(2025, 10, 5);

const formatted = eventDate.toLocaleDateString("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

console.log(formatted);

This produces a human-friendly string such as November 5, 2025.

5. Practical Use Cases

In most projects, Date is used for both storage and display, but the best practice is usually to store timestamps or ISO strings and format them only when needed.

6. Common Mistakes

Mistake 1: Forgetting that months are zero-based

JavaScript's date constructor treats months as 0 through 11. New developers often pass 1 for January and get the wrong month.

Problem: This creates February 15, not January 15, because the month argument starts at zero.

const wrong = new Date(2025, 1, 15);
console.log(wrong.toDateString());

Fix: Use 0 for January, 1 for February, and so on.

const correct = new Date(2025, 0, 15);
console.log(correct.toDateString());

The corrected version works because it matches JavaScript's month indexing rules.

Mistake 2: Comparing dates with == or ===

Two different Date objects are different object references, even if they represent the same moment.

Problem: Reference comparison does not compare the actual time value, so these checks usually fail even when the dates look identical.

const a = new Date(2025, 0, 1);
const b = new Date(2025, 0, 1);

console.log(a === b);

Fix: Compare the timestamps with getTime() or valueOf().

const a = new Date(2025, 0, 1);
const b = new Date(2025, 0, 1);

console.log(a.getTime() === b.getTime());

The corrected version works because timestamps compare the actual moment in time.

Mistake 3: Assuming parsed date strings are always reliable

String parsing with Date can be inconsistent if the format is not ISO 8601 or otherwise well supported. Some strings may create an invalid date without an obvious error.

Problem: A date string can produce Invalid Date, and methods such as getTime() then return NaN.

const parsed = new Date("15/01/2025");

console.log(parsed.toString());
console.log(parsed.getTime());

Fix: Use a reliable format such as ISO 8601, or build the date from numeric parts yourself.

const parsed = new Date("2025-01-15T00:00:00Z");

if (Number.isNaN(parsed.getTime())) {
  console.log("Invalid date");
}

The corrected version works because ISO-style input is far more predictable across JavaScript engines.

7. Best Practices

Practice 1: Store timestamps or ISO strings, not formatted text

Formatted strings are good for display, but they are a poor storage format because they depend on locale and are harder to compare.

const stored = "2025-01-15T14:30:00.000Z";
const date = new Date(stored);

This approach keeps your data consistent and easy to reconstruct later.

Practice 2: Use UTC when you need absolute time

If the time must mean the same thing everywhere, use UTC methods or ISO timestamps with Z at the end.

const utcDate = new Date("2025-01-15T12:00:00Z");

console.log(utcDate.toISOString());

UTC avoids many time zone surprises when data is shared across systems.

Practice 3: Validate dates before using them

A date object can exist but still be invalid. Check it before formatting or calculating with it.

const candidate = new Date("not a date");

if (Number.isNaN(candidate.getTime())) {
  console.log("Please enter a valid date");
}

This prevents downstream bugs from invalid input.

8. Limitations and Edge Cases

If you need calendar-only values, such as a birthday without a time of day, be careful: Date still represents a moment in time, so time zone conversion can shift the displayed day.

9. Practical Mini Project

This mini project builds a small function that prints a countdown message for an event. It combines creation, comparison, and formatting in one place.

function daysUntilEvent(eventDate) {
  const now = new Date();
  const target = new Date(eventDate);

  if (Number.isNaN(target.getTime())) {
    return "Invalid event date";
  }

  const msPerDay = 24 * 60 * 60 * 1000;
  const diff = target.getTime() - now.getTime();
  const days = Math.ceil(diff / msPerDay);

  if (days < 0) {
    return "The event has already passed";
  }

  return `${days} day(s) left`;
}

console.log(daysUntilEvent("2025-12-31T00:00:00Z"));

This example shows a practical workflow: validate the input, compare timestamps, and return a readable result.

10. Key Points

11. Practice Exercise

Expected output: A readable, validated long-form date string.

Hint: Check the result with Number.isNaN(date.getTime()), then use toLocaleDateString() with options.

function formatMeetingDate(dateString) {
  const date = new Date(dateString);

  if (Number.isNaN(date.getTime())) {
    return "Invalid date";
  }

  return date.toLocaleDateString("en-US", {
    weekday: "long",
    year: "numeric",
    month: "long",
    day: "numeric"
  });
}

console.log(formatMeetingDate("2025-03-12T09:00:00Z"));
console.log(formatMeetingDate("hello"));

12. Final Summary

Date is the standard JavaScript object for working with moments in time, timestamps, and readable date output. It is simple to create, but its behavior around months, parsing, and time zones requires attention.

For most everyday work, the safest approach is to store dates as ISO strings or timestamps, compare values with getTime(), and format output only when you display it to a user. That keeps your code predictable and reduces time zone surprises.

If you want to go further, the next topic to learn is JavaScript time zones and locale formatting, because those are the pieces that most often determine whether a date feature feels correct to users.