I recently had an interesting problem to solve around displaying TimeSpan
values in Angular.
Table of contents
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)