jsguides

Date

The Date object is a built-in JavaScript object that represents dates and times. It provides methods for creating, parsing, manipulating, and formatting dates across different time zones and formats.

Creating date objects

Create an instance using the Date constructor:

// Current date and time
const now = new Date();
// 2026-03-14T06:38:00.000Z

// From a date string
const fromString = new Date("2026-03-14T12:00:00Z");
// 2026-03-14T12:00:00.000Z

// From year, month (0-indexed), day, hour, minute, second, millisecond
const fromParts = new Date(2026, 2, 14, 12, 0, 0, 0);
// 2026-03-14T11:00:00.000Z (local time)

// From a timestamp (milliseconds since Unix epoch)
const fromTimestamp = new Date(1700000000000);
// 2023-11-14T22:13:20.000Z

Once you have an instance, the constructor is only the starting point. It also exposes several static methods that operate on date values without requiring an instance — they give you the current timestamp, parse strings into numeric form, and construct UTC timestamps from individual components.

Static Methods

Date.now()

Returns the current timestamp in milliseconds:

Date.now()   // 1700000000000 (current timestamp)

While Date.now() gives you the current time as a millisecond count, Date.parse() converts a date string into the same numeric format. The distinction matters when you need a specific point in time rather than right now. Keep in mind that Date.parse() behavior is implementation-dependent for non-ISO formats — always pass ISO 8601 strings for consistent results across environments.

Date.parse()

Parses a date string and returns a timestamp:

Date.parse("2026-03-14")   // 1736726400000 (midnight UTC)

Date.parse() always interprets strings as UTC. Date.UTC() accepts separate numeric arguments and also returns a UTC timestamp, but unlike the constructor, it treats every argument as a UTC value regardless of local time zone. This gives you a safe way to build a timestamp for a specific UTC moment without worrying about how the local clock offset might shift the result.

Date.UTC()

Returns the timestamp for a UTC date:

Date.UTC(2026, 2, 14)   // 1736726400000

Static methods like Date.UTC() produce numeric timestamps. The instance method toISOString() goes in the opposite direction — it takes the timestamp stored inside an instance and formats it as a human-readable ISO 8601 string in UTC. When you need a standardized string representation for logging, serialization, or API responses, toISOString() is the method to reach for.

Date.prototype.toISOString()

Formats the date as an ISO 8601 string:

const date = new Date(2026, 2, 14, 12, 0, 0);
date.toISOString()   // "2026-03-14T11:00:00.000Z"

The static methods are useful for timestamp generation and parsing, but for working with individual parts of a date, you need the instance getter methods. Each getter extracts a specific component — year, month, day, hour, and so on — from the internal timestamp so you can read one piece without parsing the whole string.

Getting date components

Extract individual components from a Date:

const date = new Date("2026-03-14T12:30:45.123Z");

date.getFullYear()         // 2026
date.getMonth()            // 2 (March, 0-indexed)
date.getDate()             // 14 (day of month)
date.getDay()              // 6 (Saturday, 0 = Sunday)
date.getHours()            // 12
date.getMinutes()          // 30
date.getSeconds()          // 45
date.getMilliseconds()     // 123
date.getTime()             // 1736701845123 (timestamp)

// UTC variants
date.getUTCFullYear()      // 2026
date.getUTCMonth()         // 2
date.getUTCDate()          // 14

Getters read components from the internal timestamp without changing anything. The corresponding setter methods mutate the Date object in place, updating the timestamp so the modified component takes the new value while the remaining components stay as they were. Each setter returns the updated timestamp as a number, which gives you the option to chain calls or store the result for later use.

Setting date components

Modify specific components of a Date:

const date = new Date("2026-03-14T12:00:00Z");

date.setFullYear(2027)           // Updates year
date.setMonth(0)                 // Sets to January
date.setDate(1)                  // Sets to 1st of month
date.setHours(23)                // Sets hour to 23
date.setMinutes(59)               // Sets minutes
date.setSeconds(0)                // Clears seconds
date.setMilliseconds(500)        // Sets milliseconds
date.setTime(1736726400000)      // Sets from timestamp

Once you can read and write individual components, you can also manipulate dates through arithmetic. Because Date objects coerce to timestamps through their valueOf() method, subtracting two Date instances produces a difference in milliseconds, and adding a millisecond count to a timestamp shifts the moment by that exact duration.

Date Arithmetic

Perform calculations with dates:

const start = new Date("2026-01-01");
const end = new Date("2026-12-31");

// Difference in milliseconds
const diff = end - start;
// 364 * 24 * 60 * 60 * 1000 = 31449600000

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

addDays(new Date("2026-03-14"), 7)   // 2026-03-21

Internal timestamps and arithmetic give you precision, but displaying dates requires formatting. The Date object includes several methods that convert the internal timestamp into locale-aware or standard string representations. Each formatting method targets a different output context — a full string with time and time zone for logging, a date-only form for calendars, or a locale-specific display for user-facing text.

Formatting

Format dates for display:

const date = new Date("2026-03-14T12:30:00Z");

date.toString()         
// "Sat Mar 14 2026 12:30:00 GMT+0000"

date.toDateString()     
// "Sat Mar 14 2026"

date.toTimeString()     
// "12:30:00 GMT+0000"

date.toISOString()      
// "2026-03-14T12:30:00.000Z"

date.toLocaleString()   
// "3/14/2026, 12:30:00 PM" (locale-dependent)

date.toLocaleDateString()
// "3/14/2026"

date.toLocaleTimeString()
// "12:30:00 PM"

Formatting methods like toString() and toLocaleString() are affected by the runtime’s local time zone, but they do not give you explicit control over how that zone shapes the output. For time zone-aware formatting — displaying a specific time in a specific region’s offset — you need the Intl.DateTimeFormat API, which gives you named time zone support and full control over which components appear in the formatted string.

Working with time zones

Handle different time zones:

const date = new Date("2026-03-14T12:00:00Z");

// Get timezone offset in minutes
date.getTimezoneOffset()   // 0 for UTC

// Using Intl for locale-aware formatting
const formatter = new Intl.DateTimeFormat("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric",
  hour: "2-digit",
  minute: "2-digit",
  timeZoneName: "short"
});

formatter.format(date)   // "March 14, 2026, 12:00 PM UTC"

Absolute formatting with time zones produces fixed date and time strings. But many user interfaces benefit from relative displays that show how long ago something happened instead of an absolute timestamp. You can calculate relative time by comparing the target timestamp to Date.now() and breaking down the millisecond difference into days, hours, minutes, and seconds.

Relative Time

Create relative time displays:

function relativeTime(date) {
  const now = Date.now();
  const diff = now - date.getTime();
  
  const seconds = Math.floor(diff / 1000);
  const minutes = Math.floor(seconds / 60);
  const hours = Math.floor(minutes / 60);
  const days = Math.floor(hours / 24);
  
  if (days > 0) return `${days} day${days > 1 ? "s" : ""} ago`;
  if (hours > 0) return `${hours} hour${hours > 1 ? "s" : ""} ago`;
  if (minutes > 0) return `${minutes} minute${minutes > 1 ? "s" : ""} ago`;
  return `${seconds} seconds ago`;
}

relativeTime(new Date(Date.now() - 3600000))   // "1 hour ago"

Relative time calculations assume you already have a valid Date object. When the input comes from users or external sources, you need to parse strings safely. The Date constructor accepts strings, but it returns an Invalid Date for malformed input — a condition you can detect by checking whether getTime() returns NaN. Always validate before passing a parsed date into downstream calculations that assume a real timestamp.

Parsing Dates

Safely parse dates from user input:

function parseDate(input) {
  const date = new Date(input);
  if (isNaN(date.getTime())) {
    return null; // Invalid date
  }
  return date;
}

parseDate("2026-03-14")      // Valid Date
parseDate("invalid")         // null
parseDate("2026-13-45")      // null

Month indexing

The Date constructor and its getMonth()/setMonth() methods use zero-based month numbers: January is 0, December is 11. This is one of the most common sources of off-by-one bugs when working with dates. When constructing a date from parts, always subtract 1 from the human month number, and when displaying a month, always add 1 back. The day-of-month (getDate()) is one-based, which makes the asymmetry worse — new Date(2026, 2, 14) means March 14, not February 14.

Timestamps and the Unix epoch

JavaScript dates are stored internally as a 64-bit float counting milliseconds since the Unix epoch (midnight UTC on 1 January 1970). Date.now() returns this value directly, which makes it the fastest way to get the current time when you only need a number. Arithmetic on dates works by converting both sides to timestamps (date - date coerces via valueOf()), producing a difference in milliseconds. Dividing by 1000 * 60 * 60 * 24 gives days; multiplying a timestamp by zero or adding an integer offsets time by that many milliseconds.

Parsing date strings

new Date(string) and Date.parse() accept ISO 8601 strings reliably across all modern environments. For other formats, browser and Node.js implementations differ and parsing behaviour is technically implementation-defined. Always use ISO 8601 ("2026-03-14" or "2026-03-14T12:00:00Z") when constructing dates from strings. Avoid formats like "March 14, 2026" or locale-specific strings in production code — what works in one environment may return Invalid Date in another.

See Also