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 10mCode 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 WorkDayCode 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 momentCode 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

Software Engineer specialising in full-stack web application development.

Leave a Reply

This Post Has One Comment

  1. cialis from canada

    Attractive portion of content. I simply stumbled upon your site and in accession capital to claim that I acquire
    actually enjoyed account your blog posts. Anyway I’ll be subscribing
    on your feeds and even I achievement you get admission to consistently rapidly.