💡 Running Code Locally: While this online editor runs real JavaScript, some advanced examples may have limitations. For the best experience:

    • Download Node.js to run JavaScript on your computer
    • Use your browser's Developer Console (Press F12) to test code snippets
    • Create a .html file with <script> tags and open it in your browser

    Working with Dates, Timezones & Intl API

    Master JavaScript date handling, timezone conversions, and the powerful Intl API for production-grade applications

    What You'll Learn

    • How Date objects work internally
    • Creating dates correctly (UTC-safe)
    • Timezone handling and DST
    • Intl API for locale formatting
    • Relative time ("3 hours ago")
    • Avoiding the "one day off" bug

    Working with dates and timezones in JavaScript is one of the most confusing parts of the language. Developers regularly run into bugs like "one day off," "wrong timezone," "midnight shifting backwards," and "timestamps showing the wrong hour." This lesson covers the Date object internals, UTC vs local time, DST behaviour, global timezones, and the Intl API for production-grade time logic.

    ⭐ The JavaScript Date Object: What It Really Stores

    A JavaScript Date doesn't store a timezone. It stores a single number: the milliseconds since Jan 1, 1970 UTC. Everything else — local time, UTC time, formatted strings — is calculated from that number.

    The Date Object Internals

    Understanding what Date objects really store

    Try it Yourself »
    JavaScript
    const d = new Date();
    console.log(d.getTime()); // milliseconds since epoch
    
    // This single fact explains nearly all confusing behaviour:
    // - new Date("2024-01-01") may shift depending on timezone
    // - Formatting differs per user locale
    // - Midnight conversions break around DST transitions

    ⭐ Creating Dates Correctly

    Best practice: always create dates with a timezone in mind.

    Creating Dates Correctly

    Different methods to create dates with timezones

    Try it Yourself »
    JavaScript
    // Method 1: Using Date.UTC() - explicit UTC
    const d1 = new Date(Date.UTC(2025, 0, 1, 12, 0));
    console.log(d1.toISOString());
    
    // Method 2: Using ISO with "Z" for UTC
    const d2 = new Date("2025-01-01T12:00:00Z");
    console.log(d2.toISOString());
    
    // Method 3: Local time (dangerous but sometimes needed)
    const d3 = new Date(2025, 0, 1, 12, 0);
    console.log(d3.toString());

    ❌ BAD: Ambiguous input
    new Date("2025-01-01") may shift backward or forward depending on the engine, region, and browser.

    ⭐ Understanding Timezones

    Every timezone has a base offset (e.g. UTC+1), daylight savings rules, historical changes, and political changes.

    Understanding Timezones

    Working with different timezones in JavaScript

    Try it Yourself »
    JavaScript
    // Check your system timezone
    const myTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
    console.log("Your timezone:", myTimezone);
    
    // Convert a UTC date to specific timezones
    const d = new Date("2025-03-11T12:00:00Z");
    
    console.log("London:", d.toLocaleString("en-GB", { timeZone: "Europe/London" }));
    console.log("New York:", d.toLocaleString("en-US", { timeZone: "America/New_York" }));
    console.log("Tokyo:", d.toLocaleString("ja-JP", { timeZone: "Asia/Tokyo" }));
    console.log("Sydney:"
    ...

    ⭐ DST (Daylight Saving Time)

    Timezones often jump forward or backward one hour. In the UK, clocks go forward in March and back in October.

    Daylight Saving Time

    How DST affects date calculations

    Try it Yourself »
    JavaScript
    // ❌ WRONG: Adding 24 hours may not land on the next calendar day!
    const d = new Date("2025-03-30T00:00:00");
    d.setHours(d.getHours() + 24);
    console.log("After adding 24 hours:", d);
    
    // ✔ CORRECT: Add days with setDate()
    const d2 = new Date("2025-03-30T00:00:00");
    d2.setDate(d2.getDate() + 1);
    console.log("After adding 1 day:", d2);
    
    // JavaScript automatically adjusts the month/day correctly

    ⭐ Comparing Dates Correctly

    Comparing Dates

    The correct way to compare dates in JavaScript

    Try it Yourself »
    JavaScript
    const date1 = new Date("2025-01-01");
    const date2 = new Date("2025-01-01");
    
    // ❌ WRONG: Comparing object references
    if (date1 === date2) {
      console.log("same");
    } else {
      console.log("Not same (objects are different references)");
    }
    
    // ✔ CORRECT: Compare timestamps
    if (date1.getTime() === date2.getTime()) {
      console.log("Timestamps are equal!");
    }

    ⭐ The Intl API (Internationalization)

    The modern way to format dates. Handles locales, languages, 24h vs 12h, timezones, and more.

    The Intl API

    Modern date formatting with internationalization

    Try it Yourself »
    JavaScript
    const d = new Date();
    
    // Basic formatting
    console.log("US format:", new Intl.DateTimeFormat("en-US").format(d));
    console.log("UK format:", new Intl.DateTimeFormat("en-GB").format(d));
    console.log("Japanese:", new Intl.DateTimeFormat("ja-JP").format(d));
    
    // Custom formatting (recommended)
    const formatted = new Intl.DateTimeFormat("en-GB", {
      year: "numeric",
      month: "long",
      day: "2-digit",
      timeZone: "Europe/London"
    }).format(d);
    
    console.log("Custom:", formatted);

    ⭐ Intl.RelativeTimeFormat — "3 hours ago"

    Super useful for notifications, messages, and analytics dashboards.

    Intl.RelativeTimeFormat

    Displaying relative time like '3 hours ago'

    Try it Yourself »
    JavaScript
    const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
    
    console.log(rtf.format(-3, "hour"));   // "3 hours ago"
    console.log(rtf.format(2, "day"));     // "in 2 days"
    console.log(rtf.format(-1, "week"));   // "last week"
    console.log(rtf.format(1, "month"));   // "next month"
    console.log(rtf.format(-5, "minute")); // "5 minutes ago"
    
    // With numeric: "always"
    const rtfNumeric = new Intl.RelativeTimeFormat("en", { numeric: "always" });
    console.log(rtfNumeric.format(-1, "day")); // "1 d
    ...

    ⭐ Working With Timestamps

    Timestamps avoid timezone issues completely.

    Working With Timestamps

    Using timestamps to avoid timezone issues

    Try it Yourself »
    JavaScript
    // Get current timestamp
    const now = Date.now();
    console.log("Current timestamp:", now);
    
    // Convert timestamp to date
    const date = new Date(1700000000000);
    console.log("From timestamp:", date.toISOString());
    
    // Convert date to timestamp
    console.log("To timestamp:", date.getTime());
    
    // Add 30 minutes safely using timestamps
    const later = new Date(now + 30 * 60 * 1000);
    console.log("30 minutes later:", later.toISOString());

    ⭐ Avoiding the "One Day Off" Bug

    The most common JavaScript date error. When you accept dates like "2025-01-01" from forms or APIs, JavaScript guesses the timezone.

    Avoiding the 'One Day Off' Bug

    Preventing the most common date error

    Try it Yourself »
    JavaScript
    // ❌ Ambiguous - may shift a day
    const ambiguous = new Date("2025-01-01");
    console.log("Ambiguous:", ambiguous.toString());
    
    // ✔ Explicit UTC
    const utc = new Date("2025-01-01T00:00:00Z");
    console.log("Explicit UTC:", utc.toString());
    
    // ✔ Explicit offset
    const offset = new Date("2025-01-01T00:00:00+01:00");
    console.log("With offset:", offset.toString());
    
    // ✔ Best: split into UTC fields manually
    const safe = new Date(Date.UTC(2025, 0, 1));
    console.log("Date.UTC:", safe.toISOString());

    ⭐ Time Arithmetic Without Bugs

    Time Arithmetic Without Bugs

    Safe date arithmetic functions

    Try it Yourself »
    JavaScript
    // Add days safely
    function addDays(date, days) {
      const d = new Date(date);
      d.setDate(d.getDate() + days);
      return d;
    }
    
    // Add months safely (auto-handles long/short months)
    function addMonths(date, m) {
      const d = new Date(date);
      d.setMonth(d.getMonth() + m);
      return d;
    }
    
    // Add years
    function addYears(date, y) {
      const d = new Date(date);
      d.setFullYear(d.getFullYear() + y);
      return d;
    }
    
    const today = new Date();
    console.log("Today:", today.toDateString());
    console.log("+7 days:
    ...

    ⭐ Validating Dates

    Validating Dates

    How to validate user-entered dates

    Try it Yourself »
    JavaScript
    // Users might enter invalid dates like 2025-02-30
    
    function isValidDate(y, m, d) {
      const date = new Date(y, m - 1, d);
      return (
        date.getFullYear() === y &&
        date.getMonth() === m - 1 &&
        date.getDate() === d
      );
    }
    
    console.log("2025-02-28 valid:", isValidDate(2025, 2, 28)); // true
    console.log("2025-02-29 valid:", isValidDate(2025, 2, 29)); // false (not leap year)
    console.log("2024-02-29 valid:", isValidDate(2024, 2, 29)); // true (leap year)
    console.log("2025-02-30 valid:", isV
    ...

    ⭐ Complete Utility Library

    A production-ready toolkit you can use anywhere:

    Complete Utility Library

    A production-ready date toolkit

    Try it Yourself »
    JavaScript
    const TimeUtils = {
      nowUTC: () => new Date().toISOString(),
    
      fromUTC: (str) => new Date(str),
    
      toUTC: (date) => new Date(date.getTime() - date.getTimezoneOffset() * 60000),
    
      format: (date, options = {}) =>
        new Intl.DateTimeFormat("en-GB", {
          dateStyle: "medium",
          timeStyle: "short",
          timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
          ...options,
        }).format(date),
    
      addDays: (date, d) => {
        const next = new Date(date);
        next.setDate(next.getDate
    ...

    ✅ Key Takeaways

    • • JavaScript Date stores milliseconds since epoch, not timezone info
    • • Always use explicit timezones when creating dates (ISO with "Z" or Date.UTC)
    • • Use setDate() not setHours() to add days (avoids DST bugs)
    • • Compare dates with getTime(), not === operator
    • • Use Intl.DateTimeFormat for consistent, locale-aware formatting
    • • Store timestamps in UTC, display in local time
    • • Always use toISOString() for API communication

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous