[READ-ONLY] Mirror of https://github.com/flo-bit/skywatched. review movies and tv shows, based on at proto
skywatched.app
2.2 kB
80 lines
1export type Callback = (result: {
2 seconds: number;
3 count: number;
4 units: Intl.RelativeTimeFormatUnit;
5 text: string;
6}) => void;
7
8export interface RenderState {
9 date: Date | number;
10 callback: Callback;
11 formatter: Intl.RelativeTimeFormat;
12}
13
14// Array reprsenting one minute, hour, day, week, month, etc in seconds
15const cutoffs = [60, 3600, 86400, 86400 * 7, 86400 * 30, 86400 * 365, Infinity];
16
17// Array equivalent to the above but in the string representation of the units
18const formatUnits: Intl.RelativeTimeFormatUnit[] = [
19 'seconds',
20 'minutes',
21 'hours',
22 'days',
23 'weeks',
24 'months',
25 'years'
26];
27
28// function to render relative time into
29export function render(state: RenderState, now: number) {
30 const { date, callback, formatter } = state;
31
32 // Allow dates or times to be passed
33 const timeMs = typeof date === 'number' ? date : date.getTime();
34
35 // Get the amount of seconds between the given date and now
36 const delta = timeMs - now;
37 const seconds = Math.round(delta / 1000);
38
39 // Grab the ideal cutoff unit
40 const unitIndex = cutoffs.findIndex((cutoff) => cutoff > Math.abs(seconds));
41
42 // units
43 const units = formatUnits[unitIndex];
44
45 // Get the divisor to divide from the seconds. E.g. if our unit is 'day' our divisor
46 // is one day in seconds, so we can divide our seconds by this to get the # of days
47 const divisor = unitIndex ? cutoffs[unitIndex - 1] : 1;
48
49 // count of units
50 const count = Math.round(seconds / divisor);
51
52 // Intl.RelativeTimeFormat do its magic
53 callback({
54 seconds: seconds,
55 count,
56 units,
57 text: formatter.format(count, units)
58 });
59
60 // calculate time to next update, taking account rounding (e.g. it goes from 2 minutes to 1 minute at 90 seconds)
61 // and also the changeover from units (59 seconds shouldn't show as 1 minute, so at 61 seconds we schedule the next
62 // update for 1 second time)
63
64 const divisorMs = divisor * 1000;
65
66 let updateIn;
67
68 if (unitIndex) {
69 updateIn = divisorMs / 2 - (Math.abs(delta) % divisorMs);
70 if (updateIn < 0) {
71 updateIn += divisorMs;
72 }
73 } else {
74 updateIn = divisorMs - (Math.abs(delta) % divisorMs);
75 }
76
77 const updateAt = now + updateIn;
78
79 return updateAt;
80}