正在加载,请稍候…

JavaScript Date and Time: The Complete Guide

Navigate JavaScript dates — Date object, timestamps, formatting, time zones, and the new Temporal API. Includes practical examples for every common date operation.

The Date Object

JavaScript's Date represents a moment in time as milliseconds since the Unix epoch (January 1, 1970 00:00:00 UTC).

// Creating dates
new Date()                          // current moment
new Date(timestamp)                 // from milliseconds
new Date('2026-05-26')              // from ISO string (UTC midnight)
new Date('2026-05-26T14:30:00Z')    // ISO with UTC time
new Date('2026-05-26T14:30:00+05:30') // ISO with timezone offset
new Date(2026, 4, 26)               // year, month (0-indexed!), day — local time
new Date(2026, 4, 26, 14, 30, 0)   // with hours, minutes, seconds

Gotcha: Month is 0-indexed (0=January, 11=December). Day is 1-indexed. This inconsistency trips up everyone.

Getting the Current Timestamp

Date.now()              // milliseconds since epoch (most efficient)
new Date().getTime()    // same thing
+new Date()             // same, via coercion (avoid — less readable)

Extracting Components

const d = new Date('2026-05-26T14:30:00Z');

// UTC methods — independent of system timezone
d.getUTCFullYear()   // 2026
d.getUTCMonth()      // 4 (May, 0-indexed)
d.getUTCDate()       // 26 (day of month)
d.getUTCHours()      // 14
d.getUTCMinutes()    // 30
d.getUTCSeconds()    // 0
d.getUTCDay()        // 1 (Monday, 0=Sunday)

// Local methods — depend on system timezone
d.getFullYear()      // might be different depending on your timezone
d.getMonth()         // same caveat
d.getDate()
d.getHours()

Rule: Use UTC methods unless you specifically need local-time behavior. Mixed use causes subtle bugs.

Formatting Dates

Intl.DateTimeFormat (Built-in, no library needed)

const d = new Date('2026-05-26T14:30:00Z');

// US format
new Intl.DateTimeFormat('en-US').format(d)
// => "5/26/2026"

// UK format
new Intl.DateTimeFormat('en-GB').format(d)
// => "26/05/2026"

// Full readable
new Intl.DateTimeFormat('en-US', {
  year: 'numeric',
  month: 'long',
  day: 'numeric',
  hour: '2-digit',
  minute: '2-digit',
  timeZone: 'America/New_York',
}).format(d)
// => "May 26, 2026 at 10:30 AM"

// Relative time (needs a reference point)
new Intl.RelativeTimeFormat('en').format(-3, 'days')
// => "3 days ago"

ISO 8601 String

new Date().toISOString()
// => "2026-05-26T14:30:00.000Z"

// For date-only
new Date().toISOString().split('T')[0]
// => "2026-05-26"

Manual Formatting

function formatDate(date, format = 'YYYY-MM-DD') {
  const y = date.getUTCFullYear();
  const m = String(date.getUTCMonth() + 1).padStart(2, '0');
  const d = String(date.getUTCDate()).padStart(2, '0');
  const H = String(date.getUTCHours()).padStart(2, '0');
  const M = String(date.getUTCMinutes()).padStart(2, '0');

  return format
    .replace('YYYY', y)
    .replace('MM', m)
    .replace('DD', d)
    .replace('HH', H)
    .replace('mm', M);
}

formatDate(new Date(), 'YYYY-MM-DD HH:mm')
// => "2026-05-26 14:30"

Date Arithmetic

JavaScript dates don't have built-in arithmetic methods. Work with timestamps:

const now = new Date();

// Add days
const nextWeek = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000);

// Add months (timezone-safe)
const nextMonth = new Date(now);
nextMonth.setUTCMonth(nextMonth.getUTCMonth() + 1);

// Difference in days
function daysBetween(a, b) {
  const msPerDay = 24 * 60 * 60 * 1000;
  return Math.round((b.getTime() - a.getTime()) / msPerDay);
}

daysBetween(new Date('2026-01-01'), new Date('2026-05-26'))
// => 145

Comparing Dates

const a = new Date('2026-05-26');
const b = new Date('2026-06-01');

// Compare timestamps
a < b   // true
a > b   // false
a <= b  // true

// Check equality (can't use == or === — compares object references)
a.getTime() === b.getTime()  // false
a.toISOString() === b.toISOString()  // false

// Is date in the past?
new Date('2026-01-01') < Date.now()  // true (auto-coercion works here)

Time Zones

The hardest part of working with dates. JavaScript's Date stores UTC internally; display is affected by the system's local timezone.

const d = new Date('2026-05-26T12:00:00Z');  // UTC noon

// What time is this in different zones?
d.toLocaleTimeString('en-US', { timeZone: 'America/New_York' })
// => "8:00:00 AM" (EDT, UTC-4)

d.toLocaleTimeString('en-US', { timeZone: 'Asia/Tokyo' })
// => "9:00:00 PM" (JST, UTC+9)

d.toLocaleTimeString('en-US', { timeZone: 'Europe/Berlin' })
// => "2:00:00 PM" (CEST, UTC+2)

Converting to a Specific Timezone

// Get the UTC offset for a timezone at a specific moment
function getTimezoneOffset(timezone, date = new Date()) {
  const utcDate = new Date(date.toLocaleString('en-US', { timeZone: 'UTC' }));
  const tzDate = new Date(date.toLocaleString('en-US', { timeZone: timezone }));
  return (utcDate - tzDate) / 60000;  // minutes
}

// Parse a local time string as if it's in a specific timezone
function parseDateInTimezone(dateStr, timezone) {
  return new Date(
    new Intl.DateTimeFormat('en-CA', {
      timeZone: timezone,
      year: 'numeric', month: '2-digit', day: '2-digit',
    }).format(new Date(dateStr))
  );
}

Best Practice: Store UTC, Display Local

// ✅ Store timestamps in UTC (ISO 8601 or Unix ms)
const event = {
  title: 'Team standup',
  startTime: '2026-05-26T09:00:00Z',  // UTC
  timezone: 'America/New_York',       // creator's timezone
};

// Display in user's local timezone
function displayEventTime(event, userTimezone) {
  return new Intl.DateTimeFormat('en-US', {
    dateStyle: 'medium',
    timeStyle: 'short',
    timeZone: userTimezone,
  }).format(new Date(event.startTime));
}

Common Patterns

Start of Day / End of Day (UTC)

function startOfDay(date) {
  const d = new Date(date);
  d.setUTCHours(0, 0, 0, 0);
  return d;
}

function endOfDay(date) {
  const d = new Date(date);
  d.setUTCHours(23, 59, 59, 999);
  return d;
}

Is Same Day?

function isSameDay(a, b, timezone = 'UTC') {
  const fmt = new Intl.DateTimeFormat('en-CA', {
    timeZone: timezone,
    year: 'numeric', month: '2-digit', day: '2-digit',
  });
  return fmt.format(a) === fmt.format(b);
}

Format "Time Ago"

function timeAgo(date) {
  const seconds = Math.floor((Date.now() - new Date(date).getTime()) / 1000);
  const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });

  if (seconds < 60) return rtf.format(-seconds, 'second');
  if (seconds < 3600) return rtf.format(-Math.floor(seconds / 60), 'minute');
  if (seconds < 86400) return rtf.format(-Math.floor(seconds / 3600), 'hour');
  if (seconds < 2592000) return rtf.format(-Math.floor(seconds / 86400), 'day');
  if (seconds < 31536000) return rtf.format(-Math.floor(seconds / 2592000), 'month');
  return rtf.format(-Math.floor(seconds / 31536000), 'year');
}

timeAgo(new Date(Date.now() - 3 * 60 * 1000))   // "3 minutes ago"
timeAgo(new Date(Date.now() - 2 * 3600 * 1000)) // "2 hours ago"

The Temporal API (Upcoming Standard)

The Temporal API is a new standard (Stage 3 proposal as of 2026) that fixes Date's design flaws with separate types for different concepts:

// Polyfill: npm install @js-temporal/polyfill
import { Temporal } from '@js-temporal/polyfill';

// PlainDate: date without time
const date = Temporal.PlainDate.from('2026-05-26');
date.year;    // 2026
date.month;   // 5 (1-indexed, unlike Date!)
date.day;     // 26

// ZonedDateTime: date + time + timezone
const zdt = Temporal.ZonedDateTime.from('2026-05-26T09:00:00[America/New_York]');
zdt.toInstant().epochMilliseconds;  // UTC milliseconds

// Arithmetic
const tomorrow = date.add({ days: 1 });
const nextMonth = date.add({ months: 1 });

// Comparison
Temporal.PlainDate.compare(date, tomorrow)  // -1 (date < tomorrow)

Temporal provides immutable date objects, proper timezone handling, and 1-indexed months — all the things Date got wrong.

→ Convert between date formats and timestamps with the Date Time Converter.