Your Guide to Formatting Durations in JavaScript: Using formatDuration


Purpose

  • Formats a duration (difference between two dates or times) into a human-readable string.

Functionality

    • Takes an interval object as input, which typically has start and end Date objects representing the beginning and end of the duration.
    • Calculates the difference in milliseconds between the start and end dates using internal methods.
    • Breaks down the difference into individual units like years, months, days, hours, minutes, and seconds.
  1. Formats the String

    • Uses a predefined format string that specifies the order and inclusion of units.
    • By default, it separates units with spaces (" ") and uses colons (:) to separate values from their units (e.g., "2 hours 30 minutes").
  2. Provides Customization

    • Allows you to customize the output format through optional arguments:
      • format (string): A template string defining the output structure. You can include placeholders like {{ years }}, {{ months }}, etc. to represent specific units.
      • leadingZeroThreshold (number, optional): Controls when leading zeros are included for smaller units (e.g., 01 for 1 minute). Defaults to 3 (leading zeros for units less than 100 milliseconds).

Example

import { formatDuration, intervalToDuration } from 'date-fns';

const startDate = new Date(2024, 6, 9, 10, 30); // July 9, 2024, 10:30 AM
const endDate = new Date(2024, 6, 9, 15, 45); // July 9, 2024, 3:45 PM

const duration = intervalToDuration({ start: startDate, end: endDate });

const formattedDuration = formatDuration(duration); // "5 hours 15 minutes"

// Customized Format (including leading zeros for minutes)
const customFormat = formatDuration(duration, {
  format: [
    '{years} years',
    '{months} months',
    '{days} days',
    '{h} hours {mm} minutes',
    '{s} seconds',
  ].filter(unit => duration[unit] > 0).join(', '),
  leadingZeroThreshold: 1, // Include leading zeros for minutes (1 digit)
});

console.log(formattedDuration);   // "5 hours 01 minutes" (or similar depending on locale)
console.log(customFormat);        // "5 hours, 01 minutes" (custom formatting)

Key Points

  • Customize the format for specific use cases (e.g., shorter units, custom delimiters).
  • The default format prioritizes clarity for larger durations.
  • formatDuration is flexible for various formatting needs.


Shortened Format with Abbreviated Units

import { formatDuration, intervalToDuration } from 'date-fns';

const duration = intervalToDuration({ start: new Date(), end: new Date(Date.now() + 60000) }); // 1 minute duration

const formattedDuration = formatDuration(duration, {
  format: ['h', 'mm', 'ss'].filter(unit => duration[unit] > 0).join(' '),
  leadingZeroThreshold: 1,
});

console.log(formattedDuration); // Output: "1m 00s" (or similar depending on locale)
  • The output might be something like "1m 00s" for a 1-minute duration (depending on your locale).
  • Leading zeros are included for minutes (using leadingZeroThreshold: 1).
  • It includes units based on their presence in the duration object (h, mm, ss).
  • This example uses a shorter format string with spaces (' ').

Format Duration in a Different Language

import { formatDuration, intervalToDuration, setLocale } from 'date-fns';
import de from 'date-fns/locale/de'; // Import German locale

setLocale(de); // Set the locale to German

const duration = intervalToDuration({ start: new Date(), end: new Date(Date.now() + 3600000) }); // 1 hour duration

const formattedDuration = formatDuration(duration);

console.log(formattedDuration); // Output: "1 Stunde" (German for "1 hour")
  • The formatted duration will now be displayed in German (e.g., "1 Stunde" for 1 hour).
  • It sets the locale using setLocale(de).
  • This example imports the German locale (de) from date-fns.
import { formatDuration, intervalToDuration } from 'date-fns';

const duration = intervalToDuration({ start: new Date(), end: new Date(Date.now() + 7200000) }); // 2 hour duration

const formattedDuration = formatDuration(duration, {
  format: ['{h} hrs', '{mm} mins'].filter(unit => duration[unit] > 0).join(', '),
});

console.log(formattedDuration); // Output: "2 hrs, 00 mins" (custom labels and comma delimiter)
  • The output might be something like "2 hrs, 00 mins" for a 2-hour duration.
  • Units are separated by a comma and a space (', ').
  • It replaces placeholders with custom labels ("hrs" and "mins") within curly braces.
  • This example uses a custom format string with placeholders ({{h}}, {{mm}}) for units.


Manual Formatting

  • While it gives you complete control over the format, it can be more verbose and error-prone compared to dedicated libraries.
  • This approach involves manually calculating the duration components (years, months, days, hours, minutes, seconds) using milliseconds and then formatting them using string manipulation techniques like concatenation and string formatting.

Example

function formatDurationManual(milliseconds) {
  const seconds = Math.floor(milliseconds / 1000);
  const minutes = Math.floor(seconds / 60);
  const hours = Math.floor(minutes / 60);
  const days = Math.floor(hours / 24);

  const remainingHours = hours % 24;
  const remainingMinutes = minutes % 60;
  const remainingSeconds = seconds % 60;

  let formattedString = "";
  if (days > 0) {
    formattedString += `${days} day${days > 1 ? "s" : ""}`;
  }
  if (remainingHours > 0) {
    formattedString += (formattedString.length > 0 ? ", " : "") + `${remainingHours} hour${remainingHours > 1 ? "s" : ""}`;
  }
  if (remainingMinutes > 0) {
    formattedString += (formattedString.length > 0 ? ", " : "") + `${remainingMinutes} minute${remainingMinutes > 1 ? "s" : ""}`;
  }
  if (remainingSeconds > 0) {
    formattedString += (formattedString.length > 0 ? ", " : "") + `${remainingSeconds} second${remainingSeconds > 1 ? "s" : ""}`;
  }
  return formattedString || "0 seconds"; // Handle zero duration case
}

const durationInMs = 3600000; // 1 hour
const formattedDuration = formatDurationManual(durationInMs);
console.log(formattedDuration); // Output: "1 hour"

Moment.js (if already using it)

  • The syntax might be slightly different, but it offers similar functionality.
  • If you're already using Moment.js for date manipulation, it has a built-in duration object that allows formatting durations.

Example

const moment = require('moment'); // Assuming you have Moment.js loaded

const duration = moment.duration(3600000); // 1 hour duration
const formattedDuration = duration.format("h [hours], m [minutes]");

console.log(formattedDuration); // Output: "1 hours, 0 minutes"

Other Date/Time Libraries

  • Several other date/time libraries in JavaScript offer similar formatting capabilities. Explore options like Luxon or Day.js if date-fns doesn't suit your specific needs.
  • formatDuration from date-fns is often a good choice due to its simplicity, flexibility, and focus on common formatting needs. However, if you need more control or already have other libraries in use, explore the alternatives.
  • Consider factors like:
    • Complexity of formatting requirements.
    • Existing dependencies in your project.
    • Need for additional date/time manipulation features.