I recently had an interesting problem to solve around displaying TimeSpan values in Angular.

Introduction

My API happens to be written in .NET Core using C#, which returns a timespan representing a duration value.

Our aim is to convert TimeSpan values to the display format 1d 1h 10m.

As an example: "15:35:00" should convert to 2d 1h 35m, where 1 day = 7.5 hours.

A pipe allows us to use the code in an Angular component template like below, where total time is a string-based timespan variable.

{{totalTime | workDay}} // outputs 5d 3h 10m
Code language: JavaScript (javascript)

This conversion could be implemented in the API, however, we want to keep our API more flexible and not disturb existing API consumers.

Creating a pipe

Let’s generate a new pipe using the CLI:

ng generate pipe WorkDay
Code language: Bash (bash)

We will perform the conversion with the help of an open-source date handling library moment from npm.

Install moment in your project:

npm install moment
Code language: Bash (bash)

Thanks to moment package, we can find the total minutes in a time span value using:

const totalMinutes = moment.duration(value).asMinutes();
Code language: TypeScript (typescript)

We can divide total minutes by our idea of work day duration, which happens to be 7.5 hours i.e. 450 minutes (7.5*60).

import { Pipe, PipeTransform } from '@angular/core'; import * as moment from 'moment'; @Pipe({ name: 'workDay' }) export class WorkDayPipe implements PipeTransform { transform(value: string): string { // Parse given value to moment duration let totalMinutes = moment.duration(value).asMinutes(); let days = Math.floor(totalMinutes / 450); let hours = 0; let minutes = 0; const dayRem = totalMinutes % 450; if (dayRem > 0) { hours = Math.floor(dayRem / 60); minutes = Math.floor(dayRem % 60); } return `${days}d ${hours}h ${minutes}m`; } }
Code language: TypeScript (typescript)

Finally, let’s put in some test cases to ensure our pipe transforms the values as expected.

import { WorkDayPipe } from './work-day.pipe'; describe('WorkDayPipe', () => { it('create an instance', () => { const pipe = new WorkDayPipe(); expect(pipe).toBeTruthy(); }); it('returns formatted value for 00:00:00', () => { const pipe = new WorkDayPipe(); const result = pipe.transform('00:00:00'); expect(result).toBe('0d 0h 0m'); }); it('returns formatted value for 02:00:00', () => { const pipe = new WorkDayPipe(); const result = pipe.transform('02:00:00'); expect(result).toBe('0d 2h 0m'); }); it('returns formatted value for 02:30:00', () => { const pipe = new WorkDayPipe(); const result = pipe.transform('02:30:00'); expect(result).toBe('0d 2h 30m'); }); it('returns formatted value for 2.02:35:00', () => { const pipe = new WorkDayPipe(); const result = pipe.transform('2.02:35:00'); expect(result).toBe('6d 5h 35m'); }); it('returns formatted value for 13.23:20:00', () => { const pipe = new WorkDayPipe(); const result = pipe.transform('13.23:20:00'); expect(result).toBe('44d 5h 20m'); }); });
Code language: TypeScript (typescript)

Umut Esen

I am a software developer and blogger with a passion for the world wide web.

Leave a Reply