📅 Display Friendly Due Dates in Angular with a Custom Pipe

Handling dates in Angular apps goes way beyond simple formatting—especially when you’re showing deadlines, reminders, or overdue tasks. A date like 2025-07-10T00:00:00Z isn’t helpful to your users. Instead, you want to display “Due Today”, “Past due by 2 days”, or “Due in 3 days.”

In this post, I’ll show you how to build a DueDatePipe—a custom Angular pipe that turns raw dates into clear, human-readable due date messages.


💡 Why Create a Custom Pipe?

Sure, Angular comes with built-in date pipes. But when you’re building task lists, to-dos, or project dashboards, formatting alone isn’t enough. Users want to know when something is due—not just see a date.

With DueDatePipe, we can turn this:

<p>{{ task.dueDate | date }}</p>

Into this:

<p>{{ task.dueDate | dueDate }}</p>

Resulting in output like:

  • ✅ “Due Today”
  • ⏳ “Due in 3 days”
  • ⚠️ “Past due by 1 day”
  • 📆 “Due Tomorrow”

🔧 The Pipe: Full Implementation

We’ll use Angular’s @Pipe decorator and bring in date-fns for smart date handling.

import { formatDate } from '@angular/common';
import { Inject, LOCALE_ID, Pipe, PipeTransform } from '@angular/core';
import { isToday, isYesterday, isTomorrow, isPast, isFuture, differenceInCalendarDays } from 'date-fns';

@Pipe({
name: 'dueDate',
standalone: true,
})
export class DueDatePipe implements PipeTransform {

constructor(@Inject(LOCALE_ID) private locale: string) {}

transform(date: Date | string | number): string {
if (!date) return '';

const parsedDate = typeof date === 'string' || typeof date === 'number'
? new Date(date)
: date;

const now = new Date();

if (isToday(parsedDate)) {
return 'Due Today';
}

if (isFuture(parsedDate)) {
if (isTomorrow(parsedDate)) {
return 'Due Tomorrow';
}
const days = differenceInCalendarDays(parsedDate, now);
return `Due in ${days} day${days > 1 ? 's' : ''}`;
}

if (isPast(parsedDate)) {
if (isYesterday(parsedDate)) {
return 'Due Yesterday';
}
const days = differenceInCalendarDays(now, parsedDate);
return `Past due by ${days} day${days > 1 ? 's' : ''}`;
}

// Fallback for edge cases
return `Due ${formatDate(parsedDate, 'MMM dd, yyyy', this.locale)}`;
}
}

🧠 How It Works

  • Input flexibility: Accepts Date, string, or timestamp.
  • Smart logic using date-fns:
    • isToday → “Due Today”
    • isTomorrow → “Due Tomorrow”
    • Future → “Due in X days”
    • isYesterday → “Due Yesterday”
    • Past → “Past due by X days”
  • Fallback: If none of the above match, we return a nicely formatted fallback date like “Due Jul 20, 2025.”

✨ Example Usage in Your Component

Here’s how you can drop it into your Angular template:

<p>{{ task.dueDate | dueDate }}</p>

That’s it. No extra logic in your component—your pipe handles everything.


✅ Why Use date-fns?

We’re not reinventing the wheel here. date-fns gives you readable, performant, and reliable functions like:

  • isToday()
  • isTomorrow()
  • differenceInCalendarDays()

This keeps our logic clear, reusable, and testable—unlike dealing with raw JS Date objects.


🧪 Bonus Tip: Localized Formatting

Because we inject Angular’s LOCALE_ID, our fallback date (formatDate(...)) respects your app’s locale. So “Jul 20, 2025” can become “20 Jul 2025” or whatever format your region prefers.


🏁 Final Thoughts

The DueDatePipe adds clarity and polish to any feature involving deadlines or schedules. It reduces noise, improves UX, and lets your users focus on what matters: What’s due and when?

Give it a try in your next Angular project and make your UIs instantly more intuitive.

Leave a Comment

Your email address will not be published. Required fields are marked *