Sunday, September 25, 2022

Displaying Custom Date Formats in Angular 12

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:

Working with DatePipe in Angular

 

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.

Read more JavaScript and Angular web development tutorials.

Rob Gravelle
Rob Gravelle
Rob Gravelle resides in Ottawa, Canada, and has been an IT guru for over 20 years. In that time, Rob has built systems for intelligence-related organizations such as Canada Border Services and various commercial businesses. In his spare time, Rob has become an accomplished music artist with several CDs and digital releases to his credit.

Popular Articles

Featured