
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.