JavaScript Dates & Times — Date, Intl.DateTimeFormat, and the Temporal API
In this tutorial, you will learn about JavaScript Dates & Times. We cover key concepts, practical examples, and best practices to help you master this topic.
Dates and times are notoriously tricky in JavaScript. The legacy Date object has quirks — months are zero-indexed, timezone handling is limited, and Parsing is inconsistent. Modern JavaScript provides the Intl.DateTimeFormat API for formatting, and the upcoming Temporal API promises a complete overhaul.
At DodaTech, date/time handling is critical for scheduling security scans, computing Compliance Windows, and displaying timezone-aware reports to global customers.
What You'll Learn
- Creating and manipulating Date objects
- Date formatting with Intl.DateTimeFormat
- Timezone conversion and handling
- Date arithmetic and difference calculation
- The Temporal API (future standard)
- Common pitfalls and best practices
The Date Object
Creating Dates
// Current date/time
const now = new Date();
console.log(now); // e.g., "2026-06-29T12:34:56.789Z"
// From timestamp (milliseconds since Unix epoch)
const epoch = new Date(0);
console.log(epoch); // "1970-01-01T00:00:00.000Z"
// From date string (avoid: parsing is implementation-dependent)
const fromString = new Date("2026-06-29T10:00:00");
// From components (months are 0-indexed!)
const fromComponents = new Date(2026, 5, 29, 10, 30, 0);
// ^^ June = 5
Warning: Month Indexing
// Months are 0-11, not 1-12:
const jan = new Date(2026, 0, 1); // January 1
const dec = new Date(2026, 11, 1); // December 1
// Using month names is clearer:
function makeDate(year, monthName, day) {
const months = [
"january", "february", "march", "april", "may", "june",
"july", "august", "september", "october", "november", "december"
];
const monthIndex = months.indexOf(monthName.toLowerCase());
if (monthIndex === -1) throw new Error("Invalid month");
return new Date(year, monthIndex, day);
}
Getting and Setting Components
const d = new Date(2026, 5, 29, 10, 30, 45);
console.log(d.getFullYear()); // 2026
console.log(d.getMonth()); // 5 (June)
console.log(d.getDate()); // 29
console.log(d.getDay()); // 1 (Monday; 0=Sun)
console.log(d.getHours()); // 10
console.log(d.getMinutes()); // 30
console.log(d.getSeconds()); // 45
console.log(d.getMilliseconds()); // 0
console.log(d.getTime()); // ms since epoch
// UTC variants:
console.log(d.getUTCFullYear()); // 2026
console.log(d.getUTCHours()); // depends on offset
// Setting (mutates in place):
d.setFullYear(2027);
d.setMonth(11, 25); // December 25
Date Formatting with Intl
const date = new Date(2026, 5, 29, 14, 30, 0);
// Basic formatting
console.log(new Intl.DateTimeFormat("en-US").format(date));
// "6/29/2026"
console.log(new Intl.DateTimeFormat("en-GB").format(date));
// "29/06/2026"
console.log(new Intl.DateTimeFormat("de-DE").format(date));
// "29.6.2026"
// Custom options
const formatter = new Intl.DateTimeFormat("en-US", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
timeZoneName: "short"
});
console.log(formatter.format(date));
// "Monday, June 29, 2026 at 02:30 PM GMT"
// Supported tokens: weekday (short/long/narrow)
// era, year (numeric/2-digit), month (numeric/2-digit/short/long/narrow)
// day (numeric/2-digit), hour, minute, second, timeZoneName
Timezone Handling
const date = new Date("2026-06-29T10:00:00"); // Local interpretation
// Display in different timezones
const options = {
timeZone: "America/New_York",
timeZoneName: "short"
};
console.log(date.toLocaleString("en-US", {
...options,
timeZone: "America/New_York"
}));
// List all IANA timezones (Node.js)
// const timezones = Intl.supportedValuesOf("timeZone");
// Converting between timezones
function convertTimezone(date, targetTZ) {
return new Date(date.toLocaleString("en-US", {
timeZone: targetTZ
}));
}
// Timezone offset
const offset = date.getTimezoneOffset(); // minutes from UTC
// +330 means UTC+5:30 (India)
Date Arithmetic
// Add days (milliseconds approach)
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;
}
// Difference between dates
function daysBetween(d1, d2) {
const msInDay = 86400000;
// Remove time component for date-only comparison
const t1 = new Date(d1.getFullYear(), d1.getMonth(), d1.getDate());
const t2 = new Date(d2.getFullYear(), d2.getMonth(), d2.getDate());
return Math.floor((t2 - t1) / msInDay);
}
// Check if date falls in a range
function isInRange(date, start, end) {
return date >= start && date <= end;
}
Common Pitfalls
// 1. Month is 0-indexed
new Date(2026, 0, 1); // January 1 (correct)
new Date(2026, 1, 1); // February 1 (not January!)
// 2. Date parsing is inconsistent
new Date("2026-06-29"); // UTC midnight
new Date("06/29/2026"); // Local midnight
new Date("June 29, 2026"); // Local midnight
// Always use ISO 8601 format or parse explicitly
// 3. Comparison uses timestamps
const d1 = new Date(2026, 0, 1);
const d2 = new Date(2026, 0, 1);
console.log(d1 === d2); // false (object comparison)
console.log(d1.getTime() === d2.getTime()); // true
// 4. Mutating methods
const original = new Date();
const copy = new Date(original);
copy.setDate(copy.getDate() + 1); // Won't affect original
The Temporal API (Future Standard)
Temporal is TC39's modern replacement for Date. It's in Stage 3 as of 2026:
// Active proposal, may change:
// https://github.com/tc39/proposal-temporal
// PlainDate (date without time)
// Temporal.PlainDate.from("2026-06-29");
// PlainTime (time without date)
// Temporal.PlainTime.from("14:30:00");
// ZonedDateTime (date + time + timezone)
// Temporal.ZonedDateTime.from("2026-06-29T14:30:00[America/New_York]");
// Duration (time span)
// Temporal.Duration.from({ days: 7, hours: 2 });
// Arithmetic is cleaner:
// date.add({ months: 1 });
// date.until(today); // returns Duration
Practice Questions
Write a function that returns the last day of a given month.
Write a function that lists all Mondays in a given year.
Write a function that calculates the user's age based on birthdate (accounting for leap years).
Write a function that formats a date as "X hours ago", "X days ago", "X months ago" (relative time).
Implement a countdown timer that shows remaining days, hours, minutes, and seconds.
Challenge: Recurring Schedule Parser
Build a class that parses and evaluates recurring schedule rules (similar to cron but friendlier):
"every weekday at 9am""every Monday, Wednesday at 2pm""15th of every month""last Friday of month"
Given a date, return the next occurrence. This is similar to how DodaTech schedules recurring security scans — a cron-free approach that's easier for users to configure.
Real-World Task: Timezone-Aware Event Scheduler
Write a function that takes:
- An array of user timezone IDs (e.g., ["America/New_York", "Asia/Tokyo"])
- An event time in UTC
- An event duration in hours
Returns: "optimized" meeting times that fall within 9am-5pm local for each participant.
This is the core logic behind scheduling tools, and it maps directly to DodaTech's compliance window scheduling for multi-region deployments.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro