import {
Pipe,
PipeTransform,
NgZone,
ChangeDetectorRef,
OnDestroy
} from "@angular/core";
import * as moment from 'moment-timezone';
@Pipe({
name: "timeAgo",
pure: false
})
export class TimeAgoPipe implements PipeTransform, OnDestroy {
private timer: number;
constructor(
private changeDetectorRef: ChangeDetectorRef,
private ngZone: NgZone
) {}
transform(value: string, timeZone: string = '') {
this.removeTimer();
let d = new Date(value);
let now = new Date();
let sign = Math.sign((now.getTime() - d.getTime()) / 1000);
let seconds = Math.round(Math.abs((now.getTime() - d.getTime()) / 1000));
if (timeZone) {
d = moment(value).tz(timeZone);
now = moment().tz(timeZone);
sign = Math.sign((now.valueOf() - d.valueOf()) / 1000);
seconds = Math.round(Math.abs((now.valueOf() - d.valueOf()) / 1000));
}
let timeToUpdate = Number.isNaN(seconds) ? 1000 : 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;
});
let minutes = Math.round(Math.abs(seconds / 60));
let hours = Math.round(Math.abs(minutes / 60));
let days = Math.round(Math.abs(hours / 24));
let months = Math.round(Math.abs(days / 30.416));
let years = Math.round(Math.abs(days / 365));
let future = false;
if (sign === -1) {
future = true;
}
if (Number.isNaN(seconds)) {
return "";
} else if (seconds <= 45) {
return "just now";
} else if (seconds <= 90) {
return (future) ? "Starts in 1 min" : "a minute ago";
} else if (minutes <= 45) {
return (future) ? "Starts in " + minutes + " mins" : minutes + " minutes ago";
} else if (minutes <= 90) {
return (future) ? "Starts in 1 hour" : "an hour ago";
} else if (hours <= 22) {
return (future) ? "Starts in " + hours + " hours" : hours + " hours ago";
} else if (hours <= 36) {
return (future) ? "Starts in 1 day" : "a day ago";
} else if (days <= 25) {
return (future) ? "Starts in " + days + " days" : days + " days ago";
} else if (days <= 45) {
return (future) ? "Starts in 1 month" : "a month ago";
} else if (days <= 345) {
return (future) ? "Starts in " + months + " months" : months + " months ago";
} else if (days <= 545) {
return (future) ? "a year later" : "a year ago";
} else {
// (days > 545)
return (future) ? years + " years later" : years + " years ago";
}
}
ngOnDestroy(): void {
this.removeTimer();
}
private removeTimer() {
if (this.timer) {
window.clearTimeout(this.timer);
this.timer = null;
}
}
private getSecondsUntilUpdate(seconds: number) {
let min = 60;
let hr = min * 60;
let day = hr * 24;
if (seconds < min) {
// less than 1 min, update every 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;
}
}
}