Often in the web apps, we keep track of the time associated with the other entities of the app like a post posted time, a blog published time, a question asked or answered, and so on. Generally, this data related to time is stored in the database in UTC or ISO format. Angular has an inbuilt pipe for Date, but it does not give us a relative time.
At front-end, we need to display these timings in a pleasant human-readable way like some seconds ago, days ago, weeks ago, months ago, years ago, etc. Such relative time-formatted values have become so common that several popular libraries implement utility functions that format them in a localized manner. Examples include Moment.js, Globalize, and date-fns. Out of such libraries, the Momentjs has become quite popular due to its numerous functions. Momentjs offers various Date formats functions, relative time functions, calendar time functions, and multiple local support.
If we only want to show a relative time associated with the entity, then using a library like momentjs is overkill. The minified version of momentjs is around 16.7k in size. It is 67.8k with locales support. There are Angular packages that wrap momentjs for Angular applications. As we don’t want to use functionalities other than relative time, there is no point adding momentjs to our project. Though 16.7k is not that much, we, as web developers, should reduce the size of our app as much as possible to deliver the best performance.
So let’s create a new pipe by using angular CLI command, ng g p pipes/relative-time -m=app. Add this code to this pipe.
import { Pipe, PipeTransform } from '@angular/core';
// import { DatePipe } from '@angular/common';
@Pipe({
name: 'relativeTime'
})
export class RelativeTimePipe implements PipeTransform {
// constructor(public datepipe: DatePipe){
// }
transform(value: any): any {
if (value) {
const differenceInSeconds = Math.floor((+new Date() - +new Date(value)) / 1000);
// less than 30 seconds ago will show as 'Just now'
if (differenceInSeconds < 30){
return 'Just now';
}
/*
If you want to show a relative date up to months only
like '2 months ago', '11 months ago', etc
and don't need relative dates such as 'one year ago' or 'six years ago', then
you can uncomment this section. Comment the 'year' field from the timeIntervals object and
write the upperLimit value as 31536000.
NOTE : If you are using following code block then notice that
we are using the transform function of DatePipe from 'angular/common' to format given Date value.
Don't forget to import add it to your providers array of app.module.ts.
See other formating from DatePipe here - https://angular.io/api/common/DatePipe#pre-defined-format-options
*/
// const upperLimit = 31536000;
// if(differenceInSeconds > upperLimit){
// return this.datepipe.transform(new Date(value), 'MMM d, y');
// }
// All values are in seconds
const timeIntervals = {
'year': 31536000,
'month': 2592000,
'week': 604800,
'day': 86400,
'hour': 3600,
'minute': 60,
'second': 1,
};
let counter;
for (const i in timeIntervals) {
counter = Math.floor(differenceInSeconds / timeIntervals[i]);
console.log("Counter is "+ counter);
if (counter > 0){
if (counter === 1) {
// singular (1 day ago)
return counter + ' ' + i + ' ago';
} else {
// plural (2 days ago)
return counter + ' ' + i + 's ago';
}
}
}
}
return value;
}
}
Usage -
Just like any other Angular Pipe,
<p>Published : {{ "2019-10-11T19:30:52.000Z" | relativeTime }}</p>
We have used a basic intuition to calculate the relative time of the given time. Relative time is a time difference between now and the given time. For example, suppose I published a blog two days ago. To calculate the relative time, we measured the difference between the current time and the given time, in this case, two days ago. Following this logic, we have used a simple function to calculate the relative difference between the given time and current time. We have defined an object, timeIntervals
, that contains the value for a minute, hour, day, week, and year, all in seconds. Next, We have iterated over this object to determine the relative time. It’s pretty straight forward.
Suppose, you want to show a relative date only up to months like 2 months ago, 11 months ago, etc. You don’t need relative dates such as one year ago or six years ago. You can uncomment the commented section, which contains uppperLimit
variable and ‘if(differenceInSeconds > upperLimit)’
condition. Comment the year
field from the timeIntervals object. Similarly, if you want a relative time up to weeks like 2 weeks ago, 3 weeks ago, but not older than that, then write the upperLimit value as 2592000 and comment month
and year
field from time intervals objects. If you are using the upper limit then don’t forget to import and add the DatePipe from ‘angular/common’
in the providers array of your app.module.ts. We are using the DatePipe to format the given date.
Generally, for a big app that utilizes several features modules, keep this pipe in a shared module and export it from the shared module. That will enable you to use it wherever you want.
That’s it. We have created a simple Angular Pipe, which can give us a relative time. Happy coding.😄
See also
- Rxjs - Observable vs Subject vs Behaviorsubject vs Replaysubject
- How to Add Dynamic Canonical Links in Angular