From 07d32f5cdef91ad7e2dc617858d5fa30ea2c97f0 Mon Sep 17 00:00:00 2001 From: Sebastian Martinez Date: Fri, 22 Jul 2022 12:06:38 +0200 Subject: [PATCH] Convert timestamp to relative format Signed-off-by: Sebastian Martinez --- .../projects/Commit/CommitAuthorship.svelte | 2 +- src/utils.test.ts | 37 ++++++++++++++++ src/utils.ts | 43 ++++++++++++++++++- 3 files changed, 79 insertions(+), 3 deletions(-) diff --git a/src/base/projects/Commit/CommitAuthorship.svelte b/src/base/projects/Commit/CommitAuthorship.svelte index 957a5c2d4..df5d82fdb 100644 --- a/src/base/projects/Commit/CommitAuthorship.svelte +++ b/src/base/projects/Commit/CommitAuthorship.svelte @@ -61,6 +61,6 @@  committed {/if} {/if} -  at  +   {formatTimestamp(commit.header.committerTime)} diff --git a/src/utils.test.ts b/src/utils.test.ts index 74828fcca..6bd37dece 100644 --- a/src/utils.test.ts +++ b/src/utils.test.ts @@ -155,6 +155,15 @@ describe("String Assertions", () => { .toEqual(expected); }); + test.each([ + { id: "hnrkj4c35uoyceb3d1dsscx8qq55cikrd1aio", expected: true }, + { id: "0x1234567890123456789012345678901234567890", expected: false }, + ])("isPeerId $id => $expected", ({ id, expected }) => { + expect( + utils.isPeerId(id)) + .toEqual(expected); + }); + test.each([ { oid: "a64ae9c6d572e0ad906faa9a4a7a8d43f113278c", expected: true }, { oid: "a64ae9c", expected: false } @@ -293,3 +302,31 @@ describe("Path Manipulation", () => { ).toEqual(expected); }); }); + +describe("Date Manipulation", () => { + test.each([ + { from: new Date("2022-01-01"), to: new Date("2022-02-01"), expected: 31 }, + { from: new Date("2022-01-01"), to: new Date("2022-01-02"), expected: 1 }, + { from: new Date("2022-01-01"), to: new Date("2022-01-01"), expected: 0 }, + ])("getDaysPassed expected: $expected ", ({ from, to, expected }) => { + expect( + utils.getDaysPassed(from, to) + ).toEqual(expected); + }); + test.each([ + { from: new Date("2022-01-01 12:00:00"), to: new Date("2022-01-01 12:00:00"), expected: "now" }, + { from: new Date("2022-01-01 12:00:00"), to: new Date("2022-01-01 12:00:01"), expected: "1 second ago" }, + { from: new Date("2022-01-01 12:00:00"), to: new Date("2022-01-01 12:01:01"), expected: "1 minute ago" }, + { from: new Date("2022-01-01 12:00:00"), to: new Date("2022-01-01 13:01:01"), expected: "1 hour ago" }, + { from: new Date("2022-01-01 12:00:00"), to: new Date("2022-01-02 13:01:01"), expected: "yesterday" }, + { from: new Date("2022-01-01 12:00:00"), to: new Date("2022-01-04 13:01:01"), expected: "3 days ago" }, + { from: new Date("2022-01-01 12:00:00"), to: new Date("2022-02-02 13:01:01"), expected: "last month" }, + { from: new Date("2022-01-01 12:00:00"), to: new Date("2022-04-02 13:01:01"), expected: "3 months ago" }, + { from: new Date("2022-01-01 12:00:00"), to: new Date("2023-04-02 12:00:00"), expected: "Sat, 01 Jan 2022 12:00:00 GMT" }, + { from: new Date("2022-03-05 12:00:00"), to: new Date("2026-04-02 12:00:00"), expected: "Sat, 05 Mar 2022 12:00:00 GMT" }, + ])("formatTimestamp expected: $expected", ({ from, to, expected }) => { + expect( + utils.formatTimestamp(from.getTime() / 1000, to.getTime()) + ).toEqual(expected); + }); +}); diff --git a/src/utils.ts b/src/utils.ts index 9f0c2a1a7..503b57ea8 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -246,8 +246,35 @@ export function unixTime(): number { return Math.floor(Date.now() / 1000); } -export const formatTimestamp = (t: number): string => { - return new Date(t * 1000).toLocaleString("en-EN", { dateStyle: "full", timeStyle: "long" }); +export const formatTimestamp = (timestamp: number, current = new Date().getTime()): string => { + const units: Record = { + year: 24 * 60 * 60 * 1000 * 365, + month: 24 * 60 * 60 * 1000 * 365 / 12, + day: 24 * 60 * 60 * 1000, + hour: 60 * 60 * 1000, + minute: 60 * 1000, + second: 1000 + }; + + // Multiplying timestamp with 1000 to convert from seconds to milliseconds + timestamp = timestamp * 1000; + const rtf = new Intl.RelativeTimeFormat('en', { numeric: "auto", style: 'long' }); + const elapsed = current - timestamp; + + if (elapsed > units["year"]) { + return new Date(timestamp).toUTCString(); // If it's more than a year we return early showing a Datetime string + } else if (elapsed < 0) { + return "now"; // If elapsed is a negative number we are dealing with an item from the future, and we return "now" + } + + for (const u in units) { + if (elapsed > units[u] || u == 'second') { + // We convert the division result to a negative number to get "XX [unit] ago" + return rtf.format(Math.round(elapsed / units[u]) * -1, u as Intl.RelativeTimeFormatUnit); + } + } + + return new Date(timestamp).toUTCString(); }; // Check whether the input is a Radicle ID. @@ -255,6 +282,11 @@ export function isRadicleId(input: string): boolean { return /^rad:[a-z]+:[a-zA-Z0-9]+$/.test(input); } +// Check whether the input is a Radicle Peer ID. +export function isPeerId(input: string): boolean { + return /^h[a-zA-Z0-9]+$/.test(input); +} + // Check whether the input is a SHA1 commit. export function isOid(input: string): boolean { return /^[a-fA-F0-9]{40}$/.test(input); @@ -355,6 +387,13 @@ export function parseRadicleId(urn: string): string { return urn.replace(/^rad:[a-z]+:/, ""); } +// Get amount of days passed between two dates without including the end date +export function getDaysPassed(from: Date, to: Date): number { + return Math.floor( + (to.getTime() - from.getTime()) / (24 * 60 * 60 * 1000) + ); +} + // Decode a Radicle Id (URN). export function decodeRadicleId(urn: string): Uint8Array { const encoded = parseRadicleId(urn);