Day.js: My Favorite Date Handling Library


June 4, 2025

8 min read

javascriptdate-handlinglibrariesprogrammingdayjs

dayjs

I've spent way too much time fighting with JavaScript's native Date object. You know the pain: parsing dates from APIs, formatting them for display, calculating differences, handling timezones. The native Date API is clunky, mutable, and honestly, just not fun to work with.

That's why Day.js became my go-to date library. With 16.4 million weekly downloads, it's clearly solving a real problem for developers. At just 2kB minified and gzipped (core), it's tiny. But here's the kicker: if you've used Moment.js, you already know how to use Day.js. The API is nearly identical, but without the bloat.

This isn't going to be an exhaustive reference—there are docs for that. Instead, I'll show you the parts I actually use every day, why I chose Day.js over alternatives like date-fns, and how to get the most out of it without overcomplicating things.

Basics & Everyday Operations

Installation

npm install dayjs
# or
pnpm add dayjs
# or
yarn add dayjs

That's it. No configuration needed to get started.

Core Concepts

Day.js has two key features that make it a joy to use: immutability and chainable methods. Every operation returns a new Day.js object, so you never accidentally mutate your original date. And you can chain operations together for readable, expressive code.

import dayjs from "dayjs";

// Parsing dates
const date1 = dayjs(); // Now
const date2 = dayjs("2024-12-20"); // From string
const date3 = dayjs(1703001600000); // From timestamp
const date4 = dayjs(new Date()); // From native Date

// Formatting
dayjs().format("YYYY-MM-DD"); // "2024-12-20"
dayjs().format("MMMM D, YYYY"); // "December 20, 2024"
dayjs().format("dddd"); // "Friday"

The format tokens are the same as Moment.js, so if you're migrating, you're already set.

Adding and Subtracting Time

This is where Day.js shines. Need to get a date 3 months from now? Or 2 weeks ago? Dead simple:

dayjs().add(7, "day"); // 7 days from now
dayjs().subtract(1, "month"); // 1 month ago
dayjs().add(2, "year"); // 2 years from now

// You can chain these
dayjs().add(1, "month").subtract(5, "day").format("YYYY-MM-DD");

Supported units: year, month, week, day, hour, minute, second, millisecond.

Date Comparisons

Comparing dates is straightforward:

const today = dayjs();
const tomorrow = dayjs().add(1, "day");
const yesterday = dayjs().subtract(1, "day");

today.isBefore(tomorrow); // true
today.isAfter(yesterday); // true
today.isSame(yesterday, "day"); // false
today.isSame(today, "day"); // true

// Check if date is between two dates
const start = dayjs("2024-01-01");
const end = dayjs("2024-12-31");
const check = dayjs("2024-06-15");

check.isAfter(start) && check.isBefore(end); // true

The second parameter in isSame lets you compare at different granularities: year, month, week, day, hour, minute, second.

Difference Calculations

Need to know how many days between two dates? Or hours? Easy:

const date1 = dayjs("2024-01-01");
const date2 = dayjs("2024-01-15");

date2.diff(date1, "day"); // 14
date2.diff(date1, "week"); // 2
date2.diff(date1, "month"); // 0 (less than a full month)

// You can also get the difference in milliseconds
date2.diff(date1); // 1209600000

Relative Time

Want to show "2 hours ago" or "in 3 days"? You'll need the relativeTime plugin, but it's worth it:

import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";

dayjs.extend(relativeTime);

dayjs().fromNow(); // "a few seconds ago"
dayjs().subtract(2, "hour").fromNow(); // "2 hours ago"
dayjs().add(3, "day").fromNow(); // "in 3 days"

// Or relative to a specific date
dayjs("2024-01-01").from(dayjs("2024-01-15")); // "14 days ago"
dayjs("2024-01-15").to(dayjs("2024-01-01")); // "in 14 days"

This is perfect for social feeds, activity logs, or any place you want human-readable time differences.

Day.js keeps the core library tiny by making everything else a plugin. You only import what you need, which means your bundle stays small. Here are the plugins I actually use:

RelativeTime

I already showed this above, but it's essential for any app that displays timestamps. Install it once, extend Day.js, and you're done.

CustomParseFormat

When APIs give you dates in weird formats, this plugin saves you:

import dayjs from "dayjs";
import customParseFormat from "dayjs/plugin/customParseFormat";

dayjs.extend(customParseFormat);

dayjs("12-25-2024", "MM-DD-YYYY"); // Parses custom format
dayjs("2024/12/25 14:30", "YYYY/MM/DD HH:mm"); // With time

Without this plugin, Day.js uses JavaScript's native date parsing, which can be unreliable.

Timezone

Timezones are hard. This plugin makes them manageable:

import dayjs from "dayjs";
import utc from "dayjs/plugin/utc";
import timezone from "dayjs/plugin/timezone";

dayjs.extend(utc);
dayjs.extend(timezone);

// Convert to a specific timezone
dayjs().tz("America/New_York").format();
dayjs().tz("Asia/Tokyo").format();

// Parse a date in a specific timezone
dayjs.tz("2024-12-20 10:00", "America/Los_Angeles");

Duration

Working with durations (like "2 hours 30 minutes")? This plugin helps:

import dayjs from "dayjs";
import duration from "dayjs/plugin/duration";

dayjs.extend(duration);

dayjs.duration(2, "hours").asMinutes(); // 120
dayjs.duration(90, "minutes").humanize(); // "an hour"
dayjs.duration(3661, "seconds").format("HH:mm:ss"); // "01:01:01"

Locale Support

Day.js supports 150+ locales. To use one:

import dayjs from "dayjs";
import "dayjs/locale/fr"; // French
import "dayjs/locale/es"; // Spanish
import "dayjs/locale/ja"; // Japanese

dayjs.locale("fr");
dayjs().format("MMMM"); // "décembre" instead of "December"

You can also set the locale globally or per-instance.

Core vs Plugins

Here's what you get with core vs what requires plugins:

Core features (no plugins needed): parsing standard formats, formatting, adding/subtracting time, comparisons, and calculating differences.

Plugin features: relative time (relativeTime), custom parse formats (customParseFormat), timezone support (timezone + utc), durations (duration), locales (import locale file), calendar dates (calendar), week of year (weekOfYear), and leap year checks (isLeapYear).

The beauty is you only bundle what you use. Need relative time? Add the plugin. Don't need timezones? Don't import them. Your bundle stays lean.

Performance & Why Not date-fns?

Why Day.js is Fast

Day.js is performant for three main reasons:

  1. Immutability: Every operation returns a new object, which means no defensive copying needed. The original date never changes.

  2. Tree-shaking: Since plugins are separate imports, bundlers can eliminate unused code. If you only use core Day.js, you only bundle core Day.js.

  3. Small bundle size: Core Day.js is ~2kB minified and gzipped. Compare that to Moment.js at ~67kB or even date-fns which can add up quickly if you import many functions.

The 679 kB "unpacked size" you see on npm is misleading—that's with ALL plugins included. In practice, you only import what you need, so your actual bundle is much smaller.

Bundle Size Comparison

Day.js: ~2 kB core (minified + gzipped), ~679 kB with all plugins, tree-shakeable.

Moment.js: ~67 kB, not tree-shakeable.

date-fns: ~0 kB core (functions), size varies by imports, tree-shakeable.

Day.js vs date-fns

This is the question I get asked most. Both are great, but they have different philosophies:

Day.js uses a chainable, object-oriented API (like Moment.js):

dayjs().add(1, "month").format("YYYY-MM-DD");

date-fns uses functional, pure functions:

format(add(new Date(), { months: 1 }), "yyyy-MM-dd");

When to choose Day.js:

  • You're migrating from Moment.js (API is nearly identical)
  • You prefer chainable APIs
  • You want a single object to work with
  • You need plugins for complex features (timezones, durations)

When to choose date-fns:

  • You prefer functional programming style
  • You want explicit imports for each function
  • You're building a library and want minimal dependencies
  • You only need basic date operations

Honest trade-offs:

Day.js is slightly larger if you use multiple plugins, but the API is more intuitive if you're coming from Moment.js. date-fns gives you more granular control over what you import, but you might end up importing many functions anyway.

I chose Day.js because:

  1. The API feels natural and readable
  2. Plugin system keeps core small while allowing extensibility
  3. Moment.js compatibility made migration painless
  4. For most apps, the bundle size difference is negligible

Both are excellent choices. Pick based on your team's preferences and migration path.

Real-World Use Cases

Let me show you how I actually use Day.js in real projects:

Displaying Relative Time

Perfect for activity feeds, comments, or notifications:

import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";

dayjs.extend(relativeTime);

function ActivityItem({ timestamp }: { timestamp: string }) {
  return (
    <div>
      <span>{dayjs(timestamp).fromNow()}</span>
      {/* Shows: "2 hours ago", "in 3 days", etc. */}
    </div>
  );
}

Form Date Inputs

Validating and formatting dates from forms:

function DateInput() {
  const [date, setDate] = useState("");

  function onDateChange(value: string) {
    const parsed = dayjs(value, "YYYY-MM-DD");

    if (parsed.isValid()) {
      // Date is valid, use it
      setDate(parsed.format("YYYY-MM-DD"));
    } else {
      // Show error
      console.error("Invalid date");
    }
  }

  return (
    <input
      type="date"
      value={date}
      onChange={(e)=> onDateChange(e.target.value)}
    />
  );
}

Date Range Filtering

Filtering data between two dates:

interface Transaction {
  date: string;
  amount: number;
}

function filterByDateRange(
  transactions: Transaction[],
  startDate: string,
  endDate: string
) {
  const start = dayjs(startDate);
  const end = dayjs(endDate);

  return transactions.filter((tx) => {
    const txDate = dayjs(tx.date);
    return txDate.isAfter(start) && txDate.isBefore(end);
  });
}

// Usage
const filtered = filterByDateRange(transactions, "2024-01-01", "2024-12-31");

Formatting Dates for Display

Consistent date formatting across your app:

function formatDate(date: string | Date, format: string = "MMM D, YYYY") {
  return dayjs(date).format(format);
}

// Usage
formatDate("2024-12-20"); // "Dec 20, 2024"
formatDate("2024-12-20", "YYYY-MM-DD"); // "2024-12-20"
formatDate("2024-12-20", "dddd, MMMM D"); // "Friday, December 20"

Simple Timezone Conversions

Converting server times to user's local timezone:

import dayjs from "dayjs";
import utc from "dayjs/plugin/utc";
import timezone from "dayjs/plugin/timezone";

dayjs.extend(utc);
dayjs.extend(timezone);

// Server sends UTC timestamp
const serverTime = "2024-12-20T10:00:00Z";

// Convert to user's timezone (or specific timezone)
const localTime = dayjs.utc(serverTime).local();
// or
const nyTime = dayjs.utc(serverTime).tz("America/New_York");

After working with dates in JavaScript for years, Day.js is the library I reach for every time. It's simple when you need simple, powerful when you need powerful, and it never gets in your way. That's exactly what a good library should do.

Share: