Skip to content

Instantly share code, notes, and snippets.

@SnisarOnline
Last active March 7, 2023 15:10
Show Gist options
  • Save SnisarOnline/d0b3e4d417ec7b73cf3f559e96b11fc0 to your computer and use it in GitHub Desktop.
Save SnisarOnline/d0b3e4d417ec7b73cf3f559e96b11fc0 to your computer and use it in GitHub Desktop.
An Angular pipe for converting a date string into a time ago
// Angular
import { Pipe, PipeTransform, OnDestroy, ChangeDetectorRef, NgZone } from '@angular/core';
/**
* https://github.com/AndrewPoyntz/time-ago-pipe
* An Angular pipe for converting a date string into a time ago
*
* Example :
* <span>Last {{ date | kTimeElapsed}} ago</span>
*/
@Pipe({
name: 'kTimeElapsed'
})
export class TimeElapsedPipe implements PipeTransform, OnDestroy {
private _timer: number;
/**
* Pipe Constructor
*
* @param changeDetectorRef: ChangeDetectorRef
* @param ngZone: NgZone
*/
constructor(
private changeDetectorRef: ChangeDetectorRef,
private ngZone: NgZone
) {}
/**
* @ Lifecycle sequences => https://angular.io/guide/lifecycle-hooks
*/
ngOnDestroy(): void {
this.removeTimer();
}
/**
* Transform
*
* @param value: string time
* @param textBefore: string - text Before calculated time
* @param textAfter: string - text after calculated time
*/
transform(value: string, textBefore?: string, textAfter?: string): string {
this.removeTimer();
let timeElapsed: string = '';
if (!value) {
return timeElapsed;
}
const d = new Date(value);
const now = new Date();
const seconds = Math.round(Math.abs((now.getTime() - d.getTime()) / 1000));
const timeToUpdate = this.getSecondsUntilUpdate(seconds) * 1000;
this._timer = this.ngZone.runOutsideAngular(() => {
if (typeof window !== 'undefined') {
return window.setTimeout(() => {
this.ngZone.run(() =>
this.changeDetectorRef.markForCheck()
);
}, timeToUpdate);
}
return null;
});
const minutes = Math.round(Math.abs(seconds / 60));
const hours = Math.round(Math.abs(minutes / 60));
const days = Math.round(Math.abs(hours / 24));
const months = Math.round(Math.abs(days / 30.416));
const years = Math.round(Math.abs(days / 365));
if (seconds <= 45) {
timeElapsed = 'just now';
} else if (seconds <= 90) {
timeElapsed = `${textBefore} 1 min ${textAfter}`;
} else if (minutes <= 45) {
timeElapsed = `${textBefore} ${minutes} mins ${textAfter}`;
} else if (minutes <= 90) {
timeElapsed = `${textBefore} 1 hr ${textAfter}`;
} else if (hours <= 22) {
timeElapsed = `${textBefore} ${hours} hrs ${textAfter}`;
} else if (hours <= 36) {
timeElapsed = `${textBefore} 1 day ${textAfter}`;
} else if (days <= 25) {
timeElapsed = `${textBefore} ${days} days ${textAfter}`;
} else if (days <= 45) {
timeElapsed = `${textBefore} 1 month ${textAfter}`;
} else if (days <= 345) {
timeElapsed = `${textBefore} ${months} months ${textAfter}`;
} else if (days <= 545) {
timeElapsed = `${textBefore} 1 year ${textAfter}`;
} else {
// (days > 545)
timeElapsed = `${textBefore} ${years} years ${textAfter}`;
}
return this.capitalizeFirstLetter(timeElapsed);
}
/**
* Remove _timer
*/
private removeTimer(): void {
if (this._timer) {
window.clearTimeout(this._timer);
this._timer = null;
}
}
/**
* Returns Seconds Until Update
* @param seconds: number
*/
private getSecondsUntilUpdate(seconds: number): number {
const min = 60;
const hr = min * 60;
const day = hr * 24;
if (seconds < min) {
// less than 1 min, update ever 2 secs
return 2;
} else if (seconds < hr) {
// less than an hour, update every 30 secs
return 30;
} else if (seconds < day) {
// less then a day, update every 5 mins
return 300;
} else {
// update every hour
return 3600;
}
}
private capitalizeFirstLetter(str: string): string {
return str.charAt(0).toUpperCase() + str.slice(1);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment