JavaScript Fundamentals

JavaScript Date and Time: Complete Guide

Master date and time handling in JavaScript. Learn Date objects, formatting, time zones, calculations, and modern date libraries.

By JavaScriptDoc Team
datetimejavascriptdatetimetimezone

JavaScript Date and Time: Complete Guide

Working with dates and times is a common requirement in JavaScript applications. The Date object provides functionality for handling dates, times, and time zones.

Creating Date Objects

Date Constructors

// Current date and time
const now = new Date();
console.log(now); // Current date and time

// Specific date from string
const date1 = new Date('2024-03-15');
const date2 = new Date('March 15, 2024');
const date3 = new Date('2024-03-15T10:30:00');

// Date from components
const date4 = new Date(2024, 2, 15); // Month is 0-indexed (2 = March)
const date5 = new Date(2024, 2, 15, 10, 30, 0, 0); // With time

// From timestamp (milliseconds since epoch)
const date6 = new Date(1710497400000);
const date7 = new Date(0); // Unix epoch: January 1, 1970

// Invalid dates
const invalid = new Date('invalid');
console.log(invalid); // Invalid Date
console.log(isNaN(invalid)); // true

// Date validation
function isValidDate(date) {
  return date instanceof Date && !isNaN(date);
}

Date Parsing

// Date.parse() returns timestamp
const timestamp1 = Date.parse('2024-03-15');
const timestamp2 = Date.parse('March 15, 2024 10:30:00');

// ISO 8601 format (recommended)
const isoDate = new Date('2024-03-15T10:30:00.000Z');
const isoDateLocal = new Date('2024-03-15T10:30:00'); // Local time

// Different formats
const formats = [
  '2024-03-15',
  '2024/03/15',
  '03/15/2024',
  'March 15, 2024',
  'Mar 15 2024',
  '15 Mar 2024',
  '2024-03-15 10:30:00',
  '2024-03-15T10:30:00.000Z',
];

formats.forEach((format) => {
  console.log(`${format}: ${new Date(format)}`);
});

// UTC vs Local time
const utcDate = new Date(Date.UTC(2024, 2, 15, 10, 30));
const localDate = new Date(2024, 2, 15, 10, 30);

console.log('UTC:', utcDate.toISOString());
console.log('Local:', localDate.toString());

Getting Date Components

const date = new Date('2024-03-15T10:30:45.123Z');

// Local time methods
console.log(date.getFullYear()); // 2024
console.log(date.getMonth()); // 2 (0-indexed, March)
console.log(date.getDate()); // 15 (day of month)
console.log(date.getDay()); // 5 (day of week, 0=Sunday)
console.log(date.getHours()); // Local hour
console.log(date.getMinutes()); // 30
console.log(date.getSeconds()); // 45
console.log(date.getMilliseconds()); // 123
console.log(date.getTime()); // Timestamp in milliseconds

// UTC methods
console.log(date.getUTCFullYear()); // 2024
console.log(date.getUTCMonth()); // 2
console.log(date.getUTCDate()); // 15
console.log(date.getUTCHours()); // 10 (UTC hour)
console.log(date.getUTCMinutes()); // 30

// Time zone offset
console.log(date.getTimezoneOffset()); // Minutes from UTC

// Helper functions
function getDateParts(date) {
  return {
    year: date.getFullYear(),
    month: date.getMonth() + 1, // Convert to 1-indexed
    day: date.getDate(),
    hours: date.getHours(),
    minutes: date.getMinutes(),
    seconds: date.getSeconds(),
    dayOfWeek: date.getDay(),
    timestamp: date.getTime(),
  };
}

// Day names
function getDayName(date) {
  const days = [
    'Sunday',
    'Monday',
    'Tuesday',
    'Wednesday',
    'Thursday',
    'Friday',
    'Saturday',
  ];
  return days[date.getDay()];
}

// Month names
function getMonthName(date) {
  const months = [
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December',
  ];
  return months[date.getMonth()];
}

Setting Date Components

const date = new Date();

// Set individual components
date.setFullYear(2025);
date.setMonth(11); // December (0-indexed)
date.setDate(25); // Day of month
date.setHours(18);
date.setMinutes(30);
date.setSeconds(0);
date.setMilliseconds(0);

// Set multiple components
date.setHours(20, 0, 0, 0); // hours, minutes, seconds, milliseconds

// UTC setters
date.setUTCFullYear(2025);
date.setUTCMonth(11);
date.setUTCHours(18);

// Set from timestamp
date.setTime(1735156200000);

// Chaining setters
function setDateTime(year, month, day, hours = 0, minutes = 0, seconds = 0) {
  return new Date()
    .setFullYear(year)
    .setMonth(month - 1) // Convert to 0-indexed
    .setDate(day)
    .setHours(hours, minutes, seconds, 0);
}

// Add/subtract time
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 addHours(date, hours) {
  const result = new Date(date);
  result.setHours(result.getHours() + hours);
  return result;
}

Date Formatting

Built-in Formatting Methods

const date = new Date('2024-03-15T10:30:00');

// String representations
console.log(date.toString());
// Fri Mar 15 2024 10:30:00 GMT-0700 (PDT)

console.log(date.toISOString());
// 2024-03-15T17:30:00.000Z

console.log(date.toUTCString());
// Fri, 15 Mar 2024 17:30:00 GMT

console.log(date.toDateString());
// Fri Mar 15 2024

console.log(date.toTimeString());
// 10:30:00 GMT-0700 (PDT)

console.log(date.toLocaleDateString());
// 3/15/2024

console.log(date.toLocaleTimeString());
// 10:30:00 AM

console.log(date.toLocaleString());
// 3/15/2024, 10:30:00 AM

// JSON representation
console.log(date.toJSON());
// 2024-03-15T17:30:00.000Z

Locale-Specific Formatting

const date = new Date('2024-03-15T10:30:00');

// Different locales
console.log(date.toLocaleDateString('en-US')); // 3/15/2024
console.log(date.toLocaleDateString('en-GB')); // 15/03/2024
console.log(date.toLocaleDateString('de-DE')); // 15.3.2024
console.log(date.toLocaleDateString('ja-JP')); // 2024/3/15

// With options
const options = {
  weekday: 'long',
  year: 'numeric',
  month: 'long',
  day: 'numeric',
  hour: '2-digit',
  minute: '2-digit',
  second: '2-digit',
  timeZoneName: 'short',
};

console.log(date.toLocaleString('en-US', options));
// Friday, March 15, 2024 at 10:30:00 AM PDT

// Custom formatting options
const dateOptions = {
  dateStyle: 'full', // 'full', 'long', 'medium', 'short'
};

const timeOptions = {
  timeStyle: 'medium', // 'full', 'long', 'medium', 'short'
};

// Intl.DateTimeFormat for more control
const formatter = new Intl.DateTimeFormat('en-US', {
  year: 'numeric',
  month: '2-digit',
  day: '2-digit',
  hour: '2-digit',
  minute: '2-digit',
  hour12: false,
});

console.log(formatter.format(date)); // 03/15/2024, 10:30

Custom Formatting Functions

// Format 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}`;
}

// Format time as HH:MM:SS
function formatTime(date) {
  const hours = String(date.getHours()).padStart(2, '0');
  const minutes = String(date.getMinutes()).padStart(2, '0');
  const seconds = String(date.getSeconds()).padStart(2, '0');
  return `${hours}:${minutes}:${seconds}`;
}

// Format as ISO string with timezone
function formatISO(date) {
  const offset = -date.getTimezoneOffset();
  const sign = offset >= 0 ? '+' : '-';
  const absOffset = Math.abs(offset);
  const hours = Math.floor(absOffset / 60)
    .toString()
    .padStart(2, '0');
  const minutes = (absOffset % 60).toString().padStart(2, '0');

  return date.toISOString().slice(0, -1) + sign + hours + ':' + minutes;
}

// Relative time formatting
function formatRelativeTime(date) {
  const now = new Date();
  const diff = now - date;
  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} second${seconds !== 1 ? 's' : ''} ago`;
}

// Custom format string
function customFormat(date, format) {
  const map = {
    YYYY: date.getFullYear(),
    YY: date.getFullYear().toString().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]
  );
}

// Usage
const date = new Date();
console.log(customFormat(date, 'YYYY-MM-DD HH:mm:ss'));
console.log(customFormat(date, 'DD/MM/YY'));

Date Calculations

Date Arithmetic

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

// Add/subtract with overflow handling
function addMonths(date, months) {
  const result = new Date(date);
  const originalDay = result.getDate();

  result.setMonth(result.getMonth() + months);

  // Handle month overflow (e.g., Jan 31 + 1 month)
  if (result.getDate() !== originalDay) {
    result.setDate(0); // Last day of previous month
  }

  return result;
}

// Complex date arithmetic
class DateCalculator {
  static add(
    date,
    { years = 0, months = 0, days = 0, hours = 0, minutes = 0, seconds = 0 }
  ) {
    const result = new Date(date);

    if (years) result.setFullYear(result.getFullYear() + years);
    if (months) result.setMonth(result.getMonth() + months);
    if (days) result.setDate(result.getDate() + days);
    if (hours) result.setHours(result.getHours() + hours);
    if (minutes) result.setMinutes(result.getMinutes() + minutes);
    if (seconds) result.setSeconds(result.getSeconds() + seconds);

    return result;
  }

  static subtract(date, duration) {
    return this.add(date, {
      years: -(duration.years || 0),
      months: -(duration.months || 0),
      days: -(duration.days || 0),
      hours: -(duration.hours || 0),
      minutes: -(duration.minutes || 0),
      seconds: -(duration.seconds || 0),
    });
  }
}

// Date difference
function dateDiff(date1, date2) {
  const diff = Math.abs(date2 - date1);

  return {
    milliseconds: diff,
    seconds: Math.floor(diff / 1000),
    minutes: Math.floor(diff / (1000 * 60)),
    hours: Math.floor(diff / (1000 * 60 * 60)),
    days: Math.floor(diff / (1000 * 60 * 60 * 24)),
    weeks: Math.floor(diff / (1000 * 60 * 60 * 24 * 7)),
  };
}

// Age calculation
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;
}

Date Comparisons

// Basic comparison
const date1 = new Date('2024-03-15');
const date2 = new Date('2024-03-20');

console.log(date1 < date2); // true
console.log(date1 > date2); // false
console.log(date1.getTime() === date2.getTime()); // false

// Comparison functions
function isSameDay(date1, date2) {
  return (
    date1.getFullYear() === date2.getFullYear() &&
    date1.getMonth() === date2.getMonth() &&
    date1.getDate() === date2.getDate()
  );
}

function isBefore(date1, date2) {
  return date1.getTime() < date2.getTime();
}

function isAfter(date1, date2) {
  return date1.getTime() > date2.getTime();
}

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

// Date range validation
function isDateInRange(date, startDate, endDate) {
  return date >= startDate && date <= endDate;
}

// Business days calculation
function addBusinessDays(date, days) {
  const result = new Date(date);
  let count = 0;

  while (count < days) {
    result.setDate(result.getDate() + 1);
    const dayOfWeek = result.getDay();

    // Skip weekends (0 = Sunday, 6 = Saturday)
    if (dayOfWeek !== 0 && dayOfWeek !== 6) {
      count++;
    }
  }

  return result;
}

function getBusinessDaysBetween(startDate, endDate) {
  let count = 0;
  const current = new Date(startDate);

  while (current <= endDate) {
    const dayOfWeek = current.getDay();
    if (dayOfWeek !== 0 && dayOfWeek !== 6) {
      count++;
    }
    current.setDate(current.getDate() + 1);
  }

  return count;
}

Time Zones

// Getting timezone information
const date = new Date();
console.log(date.getTimezoneOffset()); // Minutes from UTC

// Convert to different timezone
function convertToTimezone(date, timeZone) {
  return new Date(date.toLocaleString('en-US', { timeZone }));
}

// Get time in specific timezone
function getTimeInTimezone(timeZone) {
  return new Date().toLocaleString('en-US', {
    timeZone,
    dateStyle: 'short',
    timeStyle: 'medium',
  });
}

// Common timezones
const timezones = [
  'UTC',
  'America/New_York',
  'America/Chicago',
  'America/Denver',
  'America/Los_Angeles',
  'Europe/London',
  'Europe/Paris',
  'Asia/Tokyo',
  'Australia/Sydney',
];

timezones.forEach((tz) => {
  console.log(`${tz}: ${getTimeInTimezone(tz)}`);
});

// Timezone-aware date formatting
class TimezoneDate {
  constructor(date, timezone) {
    this.date = date;
    this.timezone = timezone;
  }

  format(options = {}) {
    return this.date.toLocaleString('en-US', {
      ...options,
      timeZone: this.timezone,
    });
  }

  getComponents() {
    const formatted = this.format({
      year: 'numeric',
      month: '2-digit',
      day: '2-digit',
      hour: '2-digit',
      minute: '2-digit',
      second: '2-digit',
      hour12: false,
    });

    const [date, time] = formatted.split(', ');
    const [month, day, year] = date.split('/');
    const [hour, minute, second] = time.split(':');

    return {
      year: parseInt(year),
      month: parseInt(month),
      day: parseInt(day),
      hour: parseInt(hour),
      minute: parseInt(minute),
      second: parseInt(second),
    };
  }
}

Working with Timestamps

// Current timestamp
const now = Date.now();
const timestamp = new Date().getTime();
const valueOf = new Date().valueOf();

console.log(now === timestamp); // true (approximately)

// Performance timing
function measureTime(fn) {
  const start = performance.now();
  const result = fn();
  const end = performance.now();

  return {
    result,
    time: end - start,
  };
}

// Unix timestamp conversion
function toUnixTimestamp(date) {
  return Math.floor(date.getTime() / 1000);
}

function fromUnixTimestamp(timestamp) {
  return new Date(timestamp * 1000);
}

// High-resolution timestamps
function getHighResTimestamp() {
  return performance.now() + performance.timeOrigin;
}

// Timestamp utilities
class TimestampUtils {
  static toSeconds(timestamp) {
    return Math.floor(timestamp / 1000);
  }

  static toMinutes(timestamp) {
    return Math.floor(timestamp / (1000 * 60));
  }

  static toHours(timestamp) {
    return Math.floor(timestamp / (1000 * 60 * 60));
  }

  static toDays(timestamp) {
    return Math.floor(timestamp / (1000 * 60 * 60 * 24));
  }

  static format(timestamp) {
    const date = new Date(timestamp);
    return date.toISOString();
  }
}

Practical Examples

Calendar Component

class Calendar {
  constructor(year, month) {
    this.year = year;
    this.month = month;
  }

  getDaysInMonth() {
    return new Date(this.year, this.month + 1, 0).getDate();
  }

  getFirstDayOfWeek() {
    return new Date(this.year, this.month, 1).getDay();
  }

  generateCalendar() {
    const daysInMonth = this.getDaysInMonth();
    const firstDay = this.getFirstDayOfWeek();
    const calendar = [];
    let week = new Array(firstDay).fill(null);

    for (let day = 1; day <= daysInMonth; day++) {
      week.push(day);

      if (week.length === 7) {
        calendar.push(week);
        week = [];
      }
    }

    if (week.length > 0) {
      while (week.length < 7) {
        week.push(null);
      }
      calendar.push(week);
    }

    return calendar;
  }

  getMonthName() {
    const months = [
      'January',
      'February',
      'March',
      'April',
      'May',
      'June',
      'July',
      'August',
      'September',
      'October',
      'November',
      'December',
    ];
    return months[this.month];
  }

  render() {
    const calendar = this.generateCalendar();
    const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];

    console.log(`${this.getMonthName()} ${this.year}`);
    console.log(days.join(' '));

    calendar.forEach((week) => {
      const weekStr = week
        .map((day) => (day ? String(day).padStart(3) : '   '))
        .join(' ');
      console.log(weekStr);
    });
  }
}

Countdown Timer

class CountdownTimer {
  constructor(targetDate, onUpdate, onComplete) {
    this.targetDate = new Date(targetDate);
    this.onUpdate = onUpdate;
    this.onComplete = onComplete;
    this.intervalId = null;
  }

  start() {
    this.update();
    this.intervalId = setInterval(() => this.update(), 1000);
  }

  stop() {
    if (this.intervalId) {
      clearInterval(this.intervalId);
      this.intervalId = null;
    }
  }

  update() {
    const now = new Date();
    const diff = this.targetDate - now;

    if (diff <= 0) {
      this.stop();
      if (this.onComplete) this.onComplete();
      return;
    }

    const days = Math.floor(diff / (1000 * 60 * 60 * 24));
    const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
    const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
    const seconds = Math.floor((diff % (1000 * 60)) / 1000);

    if (this.onUpdate) {
      this.onUpdate({ days, hours, minutes, seconds });
    }
  }

  getRemainingTime() {
    const now = new Date();
    const diff = this.targetDate - now;

    if (diff <= 0) return null;

    return {
      total: diff,
      days: Math.floor(diff / (1000 * 60 * 60 * 24)),
      hours: Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)),
      minutes: Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)),
      seconds: Math.floor((diff % (1000 * 60)) / 1000),
    };
  }
}

// Usage
const timer = new CountdownTimer(
  '2024-12-31T23:59:59',
  (time) => {
    console.log(
      `${time.days}d ${time.hours}h ${time.minutes}m ${time.seconds}s`
    );
  },
  () => {
    console.log('Countdown complete!');
  }
);

Date Validator

class DateValidator {
  static isValidDate(dateString) {
    const date = new Date(dateString);
    return date instanceof Date && !isNaN(date);
  }

  static isLeapYear(year) {
    return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
  }

  static isWeekend(date) {
    const day = date.getDay();
    return day === 0 || day === 6;
  }

  static isBusinessDay(date) {
    return !this.isWeekend(date);
  }

  static isFutureDate(date) {
    return date > new Date();
  }

  static isPastDate(date) {
    return date < new Date();
  }

  static isToday(date) {
    const today = new Date();
    return (
      date.getFullYear() === today.getFullYear() &&
      date.getMonth() === today.getMonth() &&
      date.getDate() === today.getDate()
    );
  }

  static validateDateRange(startDate, endDate) {
    if (!this.isValidDate(startDate) || !this.isValidDate(endDate)) {
      return { valid: false, error: 'Invalid date format' };
    }

    const start = new Date(startDate);
    const end = new Date(endDate);

    if (start > end) {
      return { valid: false, error: 'Start date must be before end date' };
    }

    return { valid: true };
  }
}

Best Practices

  1. Always validate dates

    function parseDate(dateString) {
      const date = new Date(dateString);
      if (isNaN(date)) {
        throw new Error('Invalid date');
      }
      return date;
    }
    
  2. Use ISO format for consistency

    // Good: ISO format
    const date = new Date('2024-03-15T10:30:00Z');
    
    // Avoid: Ambiguous formats
    const ambiguous = new Date('03/15/2024');
    
  3. Be careful with time zones

    // Always specify timezone when important
    const utcDate = new Date(Date.UTC(2024, 2, 15, 10, 30));
    const localDate = new Date(2024, 2, 15, 10, 30);
    
  4. Use libraries for complex operations

    // Consider using date-fns, moment.js, or dayjs
    // for complex date manipulations
    

Conclusion

JavaScript's Date object provides comprehensive date and time functionality:

  • Creating dates from various formats
  • Getting and setting date components
  • Formatting for display
  • Calculations and comparisons
  • Time zone handling
  • Practical patterns for real-world use

Key takeaways:

  • Always validate date inputs
  • Be aware of time zone differences
  • Use ISO format for consistency
  • Consider third-party libraries for complex operations
  • Test edge cases like leap years and DST
  • Remember months are 0-indexed

Master date and time handling to build robust applications with temporal logic!