As web developers may undoubtedly be aware, dates come in a wide assortment of formats, and even more still when you factor in local variations. There is no need to resort to third-party libraries to format dates in Angular, as the popular JavaScript framework provides the DatePipe for exactly that purpose. Not only does it support a variety of pre-defined formats, but you can also define your own using patterns. Finally, if that is not enough, you can extend the DatePipe class to enhance its native capabilities. In this web development tutorial, we will be creating our own named date/time formats to make them more intuitive to use.
DatePipe Basics in Angular
The name of the DatePipe to use in your templates is simply “date“. Invoked without parameters, the DatePipe formats the given date as a medium date, such as “Jan 01, 2022“, using the user machine’s local system time zone and project locale – for example, en-US. Most of the time, developers at least want to provide a format. Here is the full syntax for DatePipe, including optional parameters:
{{ date_Value | date [ : format [ : timeZone [ : locale ] ] ] }}
Read: Formatting JavaScript Date Intervals
Predefined DatePipe Formats
The Angular DatePipe boasts 12 predefined formats, including “short“, “medium“, and “long“. These formats include both the date and time. Meanwhile, the “shortDate“, “mediumDate“, and “longDate” formats omit the time portion. There are also formats for times only. I won’t be covering all of these here today, but, suffice to say, named formats such as these are a lot easier to work with than date patterns like “dd/MM/yy HH:mm“, which are also valid. In fact, we are going to create our own DatePipe to encapsulate some custom formats in the very next section.
Extending the Angular DatePipe
Our DatePipe will contain a few named formats, some that override predefined ones and some of our own making. To benefit from all that the built-in Angular DatePipe delivers, we will extend it. In addition, we will implement the PipeTransform interface. It requires us to include the transform() method, which Angular invokes when it sees our pipe in the template. It is quite versatile, so web developers can utilize it in whatever way they see fit. Here’s its signature:
transform(value: any, ...args: any[]): any
Ours fetches the pattern from a Map, using the format name as a key, before invoking the Angular DatePipe’s transform() with the mapped pattern. You will notice that its transform() is prefixed with the super parent accessor:
import { Pipe, PipeTransform } from '@angular/core'; import { DatePipe } from '@angular/common'; export enum DateFormat { short = 'short date', medium = 'medium date', long = 'long date', dateOnly = 'date only', } @Pipe({ name: 'customDate', }) export class CustomDatePipe extends DatePipe implements PipeTransform { private readonly datePatterns = new Map<string, string>([ ['short', 'd/M/y, h:mm:ss a'], ['medium', 'MMM d, y, h:mm:ss a'], ['long', 'EEEE, LLLL d, y, h:mm:ss a'], ['dateOnly', 'MMM d, y'], ]); transform(date: Date, format?: string): any { const pattern = this.datePatterns.get(format) || this.datePatterns.get('medium'); //default format return super.transform(date, pattern); } }
We then have to tell Angular about the CustomDatePipe by adding it to the declarations array in the app.module.ts file:
import { CustomDatePipe } from './custom-date.pipe'; @NgModule({ imports: [ BrowserModule, FormsModule, //... ], exports: [], declarations: [ AppComponent, CustomDatePipe ], bootstrap: [ AppComponent ] }) export class AppModule { }
Read: Parsing Dates and Time Using Luxon
Using the CustomDatePipe
To put our CustomDatePipe through its paces, let’s build a simple app that lets the user choose a format from a drop-down. The formats are associated with display strings using an Enum. That way, when the user selects an item from the list, the key is passed along to our pipe via the selectedFormat variable:
import { Component } from '@angular/core'; import { DateFormat } from './custom-date.pipe'; @Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { public dateTimeFormats = Object.keys(DateFormat); public selectedFormat: string = this.dateTimeFormats[0]; public DateFormat = DateFormat; public testDate: Date = new Date('Feb 05 2021 05:36:11 GMT-0500 (Eastern Standard Time)'); }
In the template, we will bind the selectedFormat variable to the model so that it receives the selected option value. To reference the DateFormat Enum value using a variable, we can use the Associative Array Object[key] syntax:
<mat-form-field> <mat-label>Date Format</mat-label> <mat-select [(ngModel)]="selectedFormat"> <mat-option *ngFor="let dateFormat of dateTimeFormats" [value]="dateFormat" >{{ DateFormat[dateFormat] }} </mat-option> </mat-select> </mat-form-field>
To compare our formats to the default one, we will show both. We will run the testDate through the customDate pipe to obtain the formatted date. The transform() method accepts two arguments: the date and format string. As with all Angular pipes, the first is the value that’s being transformed, so we would pipe it to our customDate pipe, using the “|” operator. Any additional arguments must be separated using a colon (:), and not a comma, as they would in JavaScript or TypeScript code:
<p> Raw Date:<br /> {{ testDate }} </p> <p> Formatted Date:<br /> {{ testDate | customDate: selectedFormat }} </p>
Here is the output for the “short” date:
You can try the app yourself on stackblitz.
Conclusion to DatePipe Formats in Angular
The built-in DatePipe is quite versatile, so you probably won’t need to develop your own unless you have a lot of custom dates that require patterns to generate. But, should the need arise, you now have the capability to build your own DatePipe.