UNPKG

1.61 kBPlain TextView Raw
1export class Timer {
2 private readonly start: Date;
3 private readonly markers: Record<string, Date | undefined> = Object.create(null);
4
5 constructor(private readonly now = () => new Date()) {
6 this.start = this.now();
7 }
8 public humanReadableElapsed(sinceMarker?: string): string {
9 const elapsedSeconds = this.elapsedSeconds(sinceMarker);
10 return Timer.humanReadableElapsedMinutes(elapsedSeconds) + Timer.humanReadableElapsedSeconds(elapsedSeconds);
11 }
12
13 public elapsedSeconds(sinceMarker?: string): number {
14 const elapsedMs = this.elapsedMs(sinceMarker);
15 return Math.floor(elapsedMs / 1000);
16 }
17
18 public elapsedMs(sinceMarker?: string): number {
19 const marker = sinceMarker && this.markers[sinceMarker];
20 if (marker) {
21 return this.now().getTime() - marker.getTime();
22 } else {
23 return this.now().getTime() - this.start.getTime();
24 }
25 }
26
27 public mark(name: string): void {
28 this.markers[name] = this.now();
29 }
30
31 private static humanReadableElapsedSeconds(elapsedSeconds: number) {
32 const restSeconds = elapsedSeconds % 60;
33 return this.formatTime('second', restSeconds);
34 }
35
36 private static humanReadableElapsedMinutes(elapsedSeconds: number) {
37 const elapsedMinutes = Math.floor(elapsedSeconds / 60);
38 if (elapsedMinutes === 0) {
39 return '';
40 } else {
41 return this.formatTime('minute', elapsedMinutes);
42 }
43 }
44
45 private static formatTime(word: 'minute' | 'second', elapsed: number) {
46 const s = elapsed === 1 ? '' : 's';
47 const blank = word === 'minute' ? ' ' : '';
48 return `${elapsed} ${word}${s}${blank}`;
49 }
50}