1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
import { sprintf } from 'sprintf-js';
import { messages } from './gettext';
export type DateType = Date | string | number;
export enum DateComponent {
day,
hour,
minute,
}
export function dateByAddingComponent(date: DateType, component: DateComponent, value: number) {
const modifiedDate = new Date(date);
switch (component) {
case DateComponent.day:
modifiedDate.setDate(modifiedDate.getDate() + value);
break;
case DateComponent.hour:
modifiedDate.setHours(modifiedDate.getHours() + value);
break;
case DateComponent.minute:
modifiedDate.setMinutes(modifiedDate.getMinutes() + value);
break;
}
return modifiedDate;
}
export class DateDiff {
private readonly fromDate: Date;
private readonly toDate: Date;
public constructor(fromDate: DateType, toDate: DateType) {
this.fromDate = new Date(fromDate);
this.toDate = new Date(toDate);
}
get milliseconds(): number {
return this.toDate.getTime() - this.fromDate.getTime();
}
get seconds(): number {
return this.floor(this.milliseconds / 1000);
}
get minutes(): number {
return this.floor(this.seconds / 60);
}
get hours(): number {
return this.floor(this.minutes / 60);
}
get days(): number {
return this.floor(this.hours / 24);
}
get months(): number {
const months = new Date(Math.abs(this.milliseconds)).getUTCMonth();
const monthsWithSign = this.milliseconds >= 0 ? months : -months;
return this.years * 12 + monthsWithSign;
}
get years(): number {
const years = new Date(Math.abs(this.milliseconds)).getUTCFullYear() - 1970;
return this.milliseconds >= 0 ? years : -years;
}
private floor(n: number): number {
return n >= 0 ? Math.floor(n) : Math.ceil(n);
}
}
export function formatRelativeDate(
fromDate: DateType,
toDate: DateType,
withSuffix = false,
): string {
const diff = new DateDiff(fromDate, toDate);
const years = Math.abs(diff.years);
const months = Math.abs(diff.months);
const days = Math.abs(diff.days);
const hours = Math.abs(diff.hours);
const minutes = Math.abs(diff.minutes);
if (!withSuffix) {
if (years > 0) {
return sprintf(messages.ngettext('1 year', '%d years', years), years);
} else if (months >= 3) {
return sprintf(messages.ngettext('1 month', '%d months', months), months);
} else if (days > 0) {
return sprintf(messages.ngettext('1 day', '%d days', days), days);
} else {
return messages.gettext('less than a day');
}
} else if (diff.milliseconds > 0) {
if (years > 0) {
return sprintf(messages.ngettext('1 year left', '%d years left', years), years);
} else if (months >= 3) {
return sprintf(messages.ngettext('1 month left', '%d months left', months), months);
} else if (days > 0) {
return sprintf(messages.ngettext('1 day left', '%d days left', days), days);
} else {
return messages.gettext('less than a day left');
}
} else {
if (years > 0) {
return sprintf(messages.ngettext('a year ago', '%d years ago', years), years);
} else if (months > 0) {
return sprintf(messages.ngettext('a month ago', '%d months ago', months), months);
} else if (days > 0) {
return sprintf(messages.ngettext('a day ago', '%d days ago', days), days);
} else if (hours > 0) {
return sprintf(messages.ngettext('an hour ago', '%d hours ago', hours), hours);
} else if (minutes > 0) {
return sprintf(messages.ngettext('a minute ago', '%d minutes ago', minutes), minutes);
} else {
return messages.gettext('less than a minute ago');
}
}
}
|