From ed2880545a15dea4c6c709ad313099170cb659cf Mon Sep 17 00:00:00 2001 From: Filipe Ferreira Date: Tue, 22 Apr 2025 16:47:45 +0100 Subject: [PATCH 1/4] feat(datetime): add format_distance_to_now function --- datetime/format_distance_to_now.ts | 30 +++++++++++++ datetime/format_distance_to_now_test.ts | 58 +++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 datetime/format_distance_to_now.ts create mode 100644 datetime/format_distance_to_now_test.ts diff --git a/datetime/format_distance_to_now.ts b/datetime/format_distance_to_now.ts new file mode 100644 index 000000000000..1ffadae03f85 --- /dev/null +++ b/datetime/format_distance_to_now.ts @@ -0,0 +1,30 @@ +import { difference } from "@std/datetime/difference"; + +/** + * Formats a given date as a relative time string (e.g., "3 minutes ago"). + * + * @param date - The date to compare with the current time. + * @returns A string representing the relative time difference. + */ +export function formatDistanceToNow(date: Date): string { + const now = new Date(); + const diff = difference(date, now); + + if (diff.years && diff.years > 0) { + return `${diff.years} year${diff.years === 1 ? "" : "s"} ago`; + } else if (diff.months && diff.months > 0) { + return `${diff.months} month${diff.months === 1 ? "" : "s"} ago`; + } else if (diff.weeks && diff.weeks > 0) { + return `${diff.weeks} week${diff.weeks === 1 ? "" : "s"} ago`; + } else if (diff.days && diff.days > 0) { + return `${diff.days} day${diff.days === 1 ? "" : "s"} ago`; + } else if (diff.hours && diff.hours > 0) { + return `${diff.hours} hour${diff.hours === 1 ? "" : "s"} ago`; + } else if (diff.minutes && diff.minutes > 0) { + return `${diff.minutes} minute${diff.minutes === 1 ? "" : "s"} ago`; + } else if (diff.seconds && diff.seconds > 0) { + return `${diff.seconds} second${diff.seconds === 1 ? "" : "s"} ago`; + } else { + return "just now"; + } +} diff --git a/datetime/format_distance_to_now_test.ts b/datetime/format_distance_to_now_test.ts new file mode 100644 index 000000000000..b28bcb3f6400 --- /dev/null +++ b/datetime/format_distance_to_now_test.ts @@ -0,0 +1,58 @@ +import { assertEquals } from "jsr:@std/assert"; +import { formatDistanceToNow } from "./format_distance_to_now.ts"; +Deno.test("formats seconds ago", () => { + const now = new Date(); + const past = new Date(now.getTime() - 30 * 1000); // 30 seconds ago + const result = formatDistanceToNow(past); + assertEquals(result, "30 seconds ago"); +}); + +Deno.test("formats minutes ago", () => { + const now = new Date(); + const past = new Date(now.getTime() - 5 * 60 * 1000); // 5 minutes ago + const result = formatDistanceToNow(past); + assertEquals(result, "5 minutes ago"); +}); + +Deno.test("formats hours ago", () => { + const now = new Date(); + const past = new Date(now.getTime() - 2 * 60 * 60 * 1000); // 2 hours ago + const result = formatDistanceToNow(past); + assertEquals(result, "2 hours ago"); +}); + +Deno.test("formats days ago", () => { + const now = new Date(); + const past = new Date(now.getTime() - 3 * 24 * 60 * 60 * 1000); // 3 days ago + const result = formatDistanceToNow(past); + assertEquals(result, "3 days ago"); +}); + +Deno.test("formats weeks ago", () => { + const now = new Date(); + const past = new Date(now.getTime() - 2 * 7 * 24 * 60 * 60 * 1000); // 2 weeks ago + const result = formatDistanceToNow(past); + assertEquals(result, "2 weeks ago"); +}); + +Deno.test("formats months ago", () => { + const now = new Date(); + const past = new Date(now); + past.setMonth(now.getMonth() - 1); // 1 month ago + const result = formatDistanceToNow(past); + assertEquals(result, "1 month ago"); +}); + +Deno.test("formats years ago", () => { + const now = new Date(); + const past = new Date(now); + past.setFullYear(now.getFullYear() - 1); // 1 year ago + const result = formatDistanceToNow(past); + assertEquals(result, "1 year ago"); +}); + +Deno.test("formats just now", () => { + const now = new Date(); + const result = formatDistanceToNow(now); + assertEquals(result, "just now"); +}); From 867a117b832f3673634d8881e190f7c6285de5ea Mon Sep 17 00:00:00 2001 From: Filipe Ferreira Date: Tue, 22 Apr 2025 16:52:42 +0100 Subject: [PATCH 2/4] fix: add license headers --- datetime/format_distance_to_now.ts | 1 + datetime/format_distance_to_now_test.ts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/datetime/format_distance_to_now.ts b/datetime/format_distance_to_now.ts index 1ffadae03f85..2ea64b333b1e 100644 --- a/datetime/format_distance_to_now.ts +++ b/datetime/format_distance_to_now.ts @@ -1,3 +1,4 @@ +// Copyright 2018-2025 the Deno authors. MIT license. import { difference } from "@std/datetime/difference"; /** diff --git a/datetime/format_distance_to_now_test.ts b/datetime/format_distance_to_now_test.ts index b28bcb3f6400..a8ef9e2557bb 100644 --- a/datetime/format_distance_to_now_test.ts +++ b/datetime/format_distance_to_now_test.ts @@ -1,5 +1,7 @@ +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "jsr:@std/assert"; import { formatDistanceToNow } from "./format_distance_to_now.ts"; + Deno.test("formats seconds ago", () => { const now = new Date(); const past = new Date(now.getTime() - 30 * 1000); // 30 seconds ago From c285c5b6204f31493993758358637133bc114461 Mon Sep 17 00:00:00 2001 From: Filipe Ferreira Date: Tue, 22 Apr 2025 16:55:54 +0100 Subject: [PATCH 3/4] fix: add export and example jsdoc --- datetime/deno.json | 3 ++- datetime/format_distance_to_now.ts | 13 ++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/datetime/deno.json b/datetime/deno.json index 1267c102e644..0f8dfa66a525 100644 --- a/datetime/deno.json +++ b/datetime/deno.json @@ -9,6 +9,7 @@ "./format": "./format.ts", "./is-leap": "./is_leap.ts", "./parse": "./parse.ts", - "./week-of-year": "./week_of_year.ts" + "./week-of-year": "./week_of_year.ts", + "./format-distance-to-now": "./format_distance_to_now.ts" } } diff --git a/datetime/format_distance_to_now.ts b/datetime/format_distance_to_now.ts index 2ea64b333b1e..26703af73fa9 100644 --- a/datetime/format_distance_to_now.ts +++ b/datetime/format_distance_to_now.ts @@ -1,11 +1,22 @@ // Copyright 2018-2025 the Deno authors. MIT license. -import { difference } from "@std/datetime/difference"; +import { difference } from "./difference.ts"; /** * Formats a given date as a relative time string (e.g., "3 minutes ago"). * * @param date - The date to compare with the current time. * @returns A string representing the relative time difference. + * @example Basic usage + * ```ts + * import { format-distance-to-now } from "@std/datetime/format-distance-to-now"; + * import { assertEquals } from "@std/assert"; + * + * const now = new Date(); + * const past = new Date(now.getTime() - 2 * 60 * 60 * 1000); // 2 hours ago + * const result = formatDistanceToNow(past); + * + * assertEquals(result, "2 hours ago"); + * ``` */ export function formatDistanceToNow(date: Date): string { const now = new Date(); From b2e355b339f551f8f39b9fe0fb6a21c9c44555a3 Mon Sep 17 00:00:00 2001 From: Filipe Ferreira Date: Tue, 22 Apr 2025 17:00:30 +0100 Subject: [PATCH 4/4] fix: add test to increase coverage --- datetime/format_distance_to_now_test.ts | 45 ++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/datetime/format_distance_to_now_test.ts b/datetime/format_distance_to_now_test.ts index a8ef9e2557bb..3408771a77af 100644 --- a/datetime/format_distance_to_now_test.ts +++ b/datetime/format_distance_to_now_test.ts @@ -9,6 +9,20 @@ Deno.test("formats seconds ago", () => { assertEquals(result, "30 seconds ago"); }); +Deno.test("formats seconds ago", () => { + const now = new Date(); + const past = new Date(now.getTime() - 1 * 1000); // 1 seconds ago + const result = formatDistanceToNow(past); + assertEquals(result, "1 second ago"); +}); + +Deno.test("formats minute ago", () => { + const now = new Date(); + const past = new Date(now.getTime() - 1 * 60 * 1000); // 1 minute ago + const result = formatDistanceToNow(past); + assertEquals(result, "1 minute ago"); +}); + Deno.test("formats minutes ago", () => { const now = new Date(); const past = new Date(now.getTime() - 5 * 60 * 1000); // 5 minutes ago @@ -16,6 +30,13 @@ Deno.test("formats minutes ago", () => { assertEquals(result, "5 minutes ago"); }); +Deno.test("formats hour ago", () => { + const now = new Date(); + const past = new Date(now.getTime() - 1 * 60 * 60 * 1000); // 1 hour ago + const result = formatDistanceToNow(past); + assertEquals(result, "1 hour ago"); +}); + Deno.test("formats hours ago", () => { const now = new Date(); const past = new Date(now.getTime() - 2 * 60 * 60 * 1000); // 2 hours ago @@ -23,6 +44,13 @@ Deno.test("formats hours ago", () => { assertEquals(result, "2 hours ago"); }); +Deno.test("formats day ago", () => { + const now = new Date(); + const past = new Date(now.getTime() - 1 * 24 * 60 * 60 * 1000); // 1 day ago + const result = formatDistanceToNow(past); + assertEquals(result, "1 day ago"); +}); + Deno.test("formats days ago", () => { const now = new Date(); const past = new Date(now.getTime() - 3 * 24 * 60 * 60 * 1000); // 3 days ago @@ -30,6 +58,13 @@ Deno.test("formats days ago", () => { assertEquals(result, "3 days ago"); }); +Deno.test("formats week ago", () => { + const now = new Date(); + const past = new Date(now.getTime() - 1 * 7 * 24 * 60 * 60 * 1000); // 1 week ago + const result = formatDistanceToNow(past); + assertEquals(result, "1 week ago"); +}); + Deno.test("formats weeks ago", () => { const now = new Date(); const past = new Date(now.getTime() - 2 * 7 * 24 * 60 * 60 * 1000); // 2 weeks ago @@ -45,7 +80,7 @@ Deno.test("formats months ago", () => { assertEquals(result, "1 month ago"); }); -Deno.test("formats years ago", () => { +Deno.test("formats year ago", () => { const now = new Date(); const past = new Date(now); past.setFullYear(now.getFullYear() - 1); // 1 year ago @@ -53,6 +88,14 @@ Deno.test("formats years ago", () => { assertEquals(result, "1 year ago"); }); +Deno.test("formats years ago", () => { + const now = new Date(); + const past = new Date(now); + past.setFullYear(now.getFullYear() - 2); // 2 years ago + const result = formatDistanceToNow(past); + assertEquals(result, "2 years ago"); +}); + Deno.test("formats just now", () => { const now = new Date(); const result = formatDistanceToNow(now);