Skip to content

Commit

Permalink
refactor: polish display utilities (#455)
Browse files Browse the repository at this point in the history
  • Loading branch information
iuioiua authored Aug 30, 2023
1 parent 8d7b42c commit 79d6c56
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 19 deletions.
58 changes: 50 additions & 8 deletions utils/display.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,56 @@
// Copyright 2023 the Deno authors. All rights reserved. MIT license.
import { difference } from "std/datetime/difference.ts";

export function pluralize(unit: number, label: string) {
return unit === 1 ? `${unit} ${label}` : `${unit} ${label}s`;
/**
* Returns a pluralized string for the given amount and unit.
*
* @example
* ```ts
* import { pluralize } from "@/utils/display.ts";
*
* pluralize(0, "meow"); // Returns "0 meows"
* pluralize(1, "meow"); // Returns "1 meow"
* pluralize(2, "meow"); // Returns "2 meows"
* ```
*/
export function pluralize(amount: number, unit: string) {
return amount === 1 ? `${amount} ${unit}` : `${amount} ${unit}s`;
}

export function timeAgo(time: number | Date) {
const minutes = difference(new Date(), new Date(time))?.minutes;
if (!minutes) return pluralize(0, "minute");
if (minutes < 60) return pluralize(~~minutes, "minute");
else if (minutes < 24 * 60) return pluralize(~~(minutes / 60), "hour");
else return pluralize(~~(minutes / (24 * 60)), "day");
/**
* Returns how long ago a given date is from now.
*
* @example
* ```ts
* import { timeAgo } from "@/utils/display.ts";
* import { SECOND, MINUTE, HOUR } from ""std/datetime/constants.ts""
*
* timeAgo(new Date(Date.now() - SECOND)); // Returns "1 second"
* timeAgo(new Date(Date.now() - 2 * MINUTE)); // Returns "2 minutes"
* timeAgo(new Date(Date.now() - 3 * HOUR)); // Returns "3 hours"
* ```
*/
export function timeAgo(date: Date) {
const now = new Date();
if (date > now) throw new Error("Timestamp must be in the past");
const match = Object.entries(
difference(now, date, {
// These units make sense for a web UI
units: [
"seconds",
"minutes",
"hours",
"days",
"weeks",
"months",
"years",
],
}),
)
.toReversed()
.find(([_, amount]) => amount > 0);
if (match === undefined) return "Now";
const [unit, amount] = match;
// Remove the last character which is an "s"
return pluralize(amount, unit.slice(0, -1));
}
22 changes: 11 additions & 11 deletions utils/display_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ Deno.test("[display] pluralize()", () => {
});

Deno.test("[display] timeAgo()", () => {
assertEquals(timeAgo(Date.now()), "0 minutes");
assertEquals(timeAgo(Date.now() - SECOND * 30), "0 minutes");
assertEquals(timeAgo(Date.now() - MINUTE), "1 minute");
assertEquals(timeAgo(Date.now() - MINUTE * 2), "2 minutes");
assertEquals(timeAgo(Date.now() - MINUTE * 59), "59 minutes");
assertEquals(timeAgo(Date.now() - HOUR), "1 hour");
assertEquals(timeAgo(Date.now() - HOUR - MINUTE * 35), "1 hour");
assertEquals(timeAgo(Date.now() - HOUR * 2), "2 hours");
assertEquals(timeAgo(Date.now() - DAY), "1 day");
assertEquals(timeAgo(Date.now() - DAY - HOUR * 12), "1 day");
assertEquals(timeAgo(Date.now() - DAY * 5), "5 days");
assertEquals(timeAgo(new Date(Date.now())), "Now");
assertEquals(timeAgo(new Date(Date.now() - SECOND * 30)), "30 seconds");
assertEquals(timeAgo(new Date(Date.now() - MINUTE)), "1 minute");
assertEquals(timeAgo(new Date(Date.now() - MINUTE * 2)), "2 minutes");
assertEquals(timeAgo(new Date(Date.now() - MINUTE * 59)), "59 minutes");
assertEquals(timeAgo(new Date(Date.now() - HOUR)), "1 hour");
assertEquals(timeAgo(new Date(Date.now() - HOUR - MINUTE * 35)), "1 hour");
assertEquals(timeAgo(new Date(Date.now() - HOUR * 2)), "2 hours");
assertEquals(timeAgo(new Date(Date.now() - DAY)), "1 day");
assertEquals(timeAgo(new Date(Date.now() - DAY - HOUR * 12)), "1 day");
assertEquals(timeAgo(new Date(Date.now() - DAY * 5)), "5 days");
});

0 comments on commit 79d6c56

Please sign in to comment.