Working with Dates and Times in JavaScript (2026)
Dates in JS are painful. Here's how to make them less so.
The Problem
const d = new Date('2026-05-16');
// Works on your machine, fails on others
// Timezone issues everywhere
// Month is 0-indexed (January = 0)
// Year before 100 = 1900 + year
Modern Solution: Use a Library
npm install dayjs # 2KB, immutable, chainable
# or: npm install date-fns # Tree-shakeable, functional
Day.js — My Go-To
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';
import relativeTime from 'dayjs/plugin/relativeTime';
dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.extend(relativeTime);
// Parse
dayjs('2026-05-16'); // May 16, 2026
dayjs.unix(1715840000); // From Unix timestamp
dayjs(); // Now
// Format
dayjs().format('YYYY-MM-DD'); // "2026-05-16"
dayjs().format('YYYY-MM-DD HH:mm:ss'); // "2026-05-16 07:20:00"
dayjs().format('ddd, MMM D, YYYY'); // "Sat, May 16, 2026"
// Manipulate
dayjs().add(7, 'day'); // Next week
dayjs().subtract(1, 'month'); // Last month
dayjs().startOf('week'); // Monday of this week
dayjs().endOf('month'); // Last day of this month
// Query
dayjs().isBefore(dayjs('2027-01-01')); // true
dayjs().isAfter(dayjs('2026-01-01')); // true
dayjs().isSame(dayjs(), 'day'); // true
// Relative time
dayjs().fromNow(); // "a few seconds ago"
dayjs('2026-06-01').fromNow(); // "in 2 weeks"
// Timezone
dayjs().tz('America/New_York').format(); // Eastern time
dayjs().tz('Asia/Shanghai').format(); // Beijing time
dayjs().utc().format(); // UTC
// Difference
dayjs('2026-12-31').diff(dayjs(), 'day'); // Days until New Year's Eve
date-fns — When You Need Tree-Shaking
import { format, addDays, subMonths, isAfter, parseISO } from 'date-fns';
const now = new Date();
format(now, 'yyyy-MM-dd'); // "2026-05-16"
addDays(now, 30); // 30 days from now
subMonths(now, 3); // 3 months ago
isAfter(new Date('2027-01-01'), now); // true
parseISO('2026-05-16T07:20:00Z'); // Date object
Vanilla JS: What You Need to Know
const now = new Date();
// Get components
now.getFullYear(); // 2026
now.getMonth(); // 4 (May! 0-indexed!)
now.getDate(); // 16
now.getDay(); // 6 (Saturday, 0=Sunday)
now.getHours(); // 7
now.getMinutes(); // 20
now.getSeconds(); // 0
now.getTime(); // Unix timestamp in ms
// Set components
const d = new Date();
d.setFullYear(2026);
d.setMonth(11); // December (0-indexed!)
d.setDate(25); // Christmas!
// Format (vanilla is ugly)
d.toISOString(); // "2026-12-25T00:00:00.000Z"
d.toLocaleDateString('en-US', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
}); // "Friday, December 25, 2026"
// Parse (careful with formats)
new Date('2026-05-16'); // OK (ISO format)
new Date('05/16/2026'); // Depends on locale!
new Date(2026, 4, 16); // Reliable (month is 0-indexed!)
// Compare
const d1 = new Date('2026-01-01');
const d2 = new Date('2026-12-31');
d1 < d2; // true
Math.abs(d2 - d1) / (1000 * 60 * 60 * 24); // Days between dates
Common Patterns
Format Duration (Human Readable)
function formatDuration(ms) {
const seconds = Math.floor(ms / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
if (days > 0) return `${days}d ${hours % 24}h`;
if (hours > 0) return `${hours}h ${minutes % 60}m`;
if (minutes > 0) return `${minutes}m ${seconds % 60}s`;
return `${seconds}s`;
}
formatDuration(3661000); // "1h 1m"
formatDuration(90061000); // "1d 1h"
Is Today Between Two Dates?
function isBetween(date, start, end) {
const d = new Date(date).setHours(0, 0, 0, 0);
const s = new Date(start).setHours(0, 0, 0, 0);
const e = new Date(end).setHours(0, 0, 0, 0);
return d >= s && d <= e;
}
isBetween(new Date(), '2026-05-01', '2026-05-31'); // true
Get All Dates in a Range
function getDateRange(start, end) {
const dates = [];
let current = new Date(start);
const stop = new Date(end);
while (current <= stop) {
dates.push(new Date(current));
current.setDate(current.getDate() + 1);
}
return dates;
}
getDateRange('2026-05-01', '2026-05-05');
// [May 1, May 2, May 3, May 4, May 5]
Countdown Timer
function countdown(targetDate) {
const update = () => {
const now = new Date();
const diff = new Date(targetDate) - now;
if (diff <= 0) return { done: true };
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);
return { days, hours, minutes, seconds };
};
return update();
}
Timezone Gotchas
// ❌ Don't do this:
new Date().toString(); // "Sat May 16 2026 07:20:00 GMT+0800..."
// ✅ Do this instead:
new Date().toISOString(); // Always UTC
Intl.DateTimeFormat('en-US', { timeZone: 'America/New_York' }).format(now);
// Get user's timezone
Intl.DateTimeFormat().resolvedOptions().timeZone; // "Asia/Shanghai"
// Convert timezone
function convertTZ(date, tz) {
return new Date(date.toLocaleString('en-US', { timeZone: tz }));
}
What's your favorite date library? Or do you suffer through vanilla JS?
Follow @armorbreak for more JavaScript content.
Top comments (0)