Skip to content

Commit 3b14ca8

Browse files
Feat/get interval (#4)
* feat: add getIntervalFromNowFormatted * add new snippet
1 parent 4f929f5 commit 3b14ca8

4 files changed

Lines changed: 210 additions & 0 deletions

File tree

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { expect, it, describe, vi, beforeEach } from 'vitest';
2+
import getIntevalFromNowFormatted, { INTERVAL_DATE_ERR } from '.';
3+
4+
describe('getRemainingTimeFormatted', () => {
5+
beforeEach(() => {
6+
vi.useFakeTimers();
7+
});
8+
9+
it('should return formatted time remaining in the future', () => {
10+
const futureDate = new Date(Date.now() + 1000 * 60 * 60 * 24); // 1 day in the future
11+
const locale = 'en-US';
12+
const result = getIntevalFromNowFormatted(futureDate, locale);
13+
expect(result).toBe('in 1 day');
14+
});
15+
16+
it('should return formatted time remaining in the past', () => {
17+
const pastDate = new Date(Date.now() - 1000 * 60 * 60 * 24); // 1 day in the past
18+
const locale = 'en-US';
19+
const result = getIntevalFromNowFormatted(pastDate, locale);
20+
expect(result).toBe('1 day ago');
21+
});
22+
23+
it('should return formatted time for 12 hours in the future', () => {
24+
const futureDate = new Date(Date.now() + 1000 * 60 * 60 * 12); // 12 hours in the future
25+
const locale = 'en-US';
26+
const result = getIntevalFromNowFormatted(futureDate, locale);
27+
expect(result).toBe('in 12 hours');
28+
});
29+
30+
it('should return formatted time for 12 minutes in the future', () => {
31+
const futureDate = new Date(Date.now() + 1000 * 60 * 12); // 12 minutes in the future
32+
const locale = 'en-US';
33+
const result = getIntevalFromNowFormatted(futureDate, locale);
34+
expect(result).toBe('in 12 minutes');
35+
});
36+
37+
it('should return formatted time in Portuguese', () => {
38+
const futureDate = new Date(Date.now() + 1000 * 60 * 60 * 24); // 1 day in the future
39+
const locale = 'pt-BR';
40+
const result = getIntevalFromNowFormatted(futureDate, locale);
41+
expect(result).toBe('em 1 dia');
42+
});
43+
44+
it('should return formatted time in Europe Portuguese', () => {
45+
const futureDate = new Date(Date.now() + 1000 * 60 * 60 * 24); // 1 day in the future
46+
const locale = 'pt-PT';
47+
const result = getIntevalFromNowFormatted(futureDate, locale);
48+
expect(result).toBe('dentro de 1 dia');
49+
});
50+
51+
it('should return formatted time in Spanish', () => {
52+
const futureDate = new Date(Date.now() + 1000 * 60 * 60 * 24); // 1 day in the future
53+
const locale = 'es-ES';
54+
const result = getIntevalFromNowFormatted(futureDate, locale);
55+
expect(result).toBe('dentro de 1 día');
56+
});
57+
58+
it('should throw for invalid date', () => {
59+
const invalidDate = new Date('invalid-date');
60+
const locale = 'en-US';
61+
expect(() => getIntevalFromNowFormatted(invalidDate, locale)).toThrowError(
62+
INTERVAL_DATE_ERR
63+
);
64+
});
65+
});
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
export const INTERVAL_DATE_ERR =
2+
'Invalid date provided. Please provide a valid Date object.';
3+
4+
/**
5+
* Formats the time interval between the given date and the current date
6+
* into a human-readable relative time string.
7+
*
8+
* @param {Date} date - The target date to calculate the interval from now.
9+
* @param {string} locale - A string with a BCP 47 language tag to specify the locale for formatting.
10+
* @returns {string} A formatted string representing the relative time interval.
11+
* @throws {TypeError} Throws an error if the provided date is not a valid Date object.
12+
*/
13+
export default function getIntervalFromNowFormatted(date, locale) {
14+
if (!(date instanceof Date) || isNaN(date.getTime())) {
15+
throw new TypeError(INTERVAL_DATE_ERR);
16+
}
17+
18+
const now = new Date();
19+
const diffMs = date.getTime() - now.getTime();
20+
21+
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'always' });
22+
23+
const seconds = diffMs / 1000;
24+
const minutes = seconds / 60;
25+
const hours = minutes / 60;
26+
const days = hours / 24;
27+
28+
if (Math.abs(days) >= 1) {
29+
return rtf.format(Math.round(days), 'day');
30+
}
31+
32+
if (Math.abs(hours) >= 1) {
33+
return rtf.format(Math.round(hours), 'hour');
34+
}
35+
36+
if (Math.abs(minutes) >= 1) {
37+
return rtf.format(Math.round(minutes), 'minute');
38+
}
39+
40+
return rtf.format(Math.round(seconds), 'second');
41+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { expect, it, describe, vi, beforeEach } from 'vitest';
2+
import getIntevalFromNowFormatted, { INTERVAL_DATE_ERR } from '.';
3+
4+
describe('getRemainingTimeFormatted', () => {
5+
beforeEach(() => {
6+
vi.useFakeTimers();
7+
});
8+
9+
it('should return formatted time remaining in the future', () => {
10+
const futureDate = new Date(Date.now() + 1000 * 60 * 60 * 24); // 1 day in the future
11+
const locale = 'en-US';
12+
const result = getIntevalFromNowFormatted(futureDate, locale);
13+
expect(result).toBe('in 1 day');
14+
});
15+
16+
it('should return formatted time remaining in the past', () => {
17+
const pastDate = new Date(Date.now() - 1000 * 60 * 60 * 24); // 1 day in the past
18+
const locale = 'en-US';
19+
const result = getIntevalFromNowFormatted(pastDate, locale);
20+
expect(result).toBe('1 day ago');
21+
});
22+
23+
it('should return formatted time for 12 hours in the future', () => {
24+
const futureDate = new Date(Date.now() + 1000 * 60 * 60 * 12); // 12 hours in the future
25+
const locale = 'en-US';
26+
const result = getIntevalFromNowFormatted(futureDate, locale);
27+
expect(result).toBe('in 12 hours');
28+
});
29+
30+
it('should return formatted time for 12 minutes in the future', () => {
31+
const futureDate = new Date(Date.now() + 1000 * 60 * 12); // 12 minutes in the future
32+
const locale = 'en-US';
33+
const result = getIntevalFromNowFormatted(futureDate, locale);
34+
expect(result).toBe('in 12 minutes');
35+
});
36+
37+
it('should return formatted time in Portuguese', () => {
38+
const futureDate = new Date(Date.now() + 1000 * 60 * 60 * 24); // 1 day in the future
39+
const locale = 'pt-BR';
40+
const result = getIntevalFromNowFormatted(futureDate, locale);
41+
expect(result).toBe('em 1 dia');
42+
});
43+
44+
it('should return formatted time in Europe Portuguese', () => {
45+
const futureDate = new Date(Date.now() + 1000 * 60 * 60 * 24); // 1 day in the future
46+
const locale = 'pt-PT';
47+
const result = getIntevalFromNowFormatted(futureDate, locale);
48+
expect(result).toBe('dentro de 1 dia');
49+
});
50+
51+
it('should return formatted time in Spanish', () => {
52+
const futureDate = new Date(Date.now() + 1000 * 60 * 60 * 24); // 1 day in the future
53+
const locale = 'es-ES';
54+
const result = getIntevalFromNowFormatted(futureDate, locale);
55+
expect(result).toBe('dentro de 1 día');
56+
});
57+
58+
it('should throw for invalid date', () => {
59+
const invalidDate = new Date('invalid-date');
60+
const locale = 'en-US';
61+
expect(() => getIntevalFromNowFormatted(invalidDate, locale)).toThrowError(
62+
INTERVAL_DATE_ERR
63+
);
64+
});
65+
});
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
export const INTERVAL_DATE_ERR =
2+
'Invalid date provided. Please provide a valid Date object.';
3+
4+
/**
5+
* Formats the time interval between the given date and the current date
6+
* into a human-readable relative time string.
7+
*/
8+
export default function getIntervalFromNowFormatted(
9+
date: Date,
10+
locale: Intl.LocalesArgument
11+
): string {
12+
if (!(date instanceof Date) || isNaN(date.getTime())) {
13+
throw new TypeError(INTERVAL_DATE_ERR);
14+
}
15+
16+
const now = new Date();
17+
const diffMs = date.getTime() - now.getTime();
18+
19+
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'always' });
20+
21+
const seconds = diffMs / 1000;
22+
const minutes = seconds / 60;
23+
const hours = minutes / 60;
24+
const days = hours / 24;
25+
26+
if (Math.abs(days) >= 1) {
27+
return rtf.format(Math.round(days), 'day');
28+
}
29+
30+
if (Math.abs(hours) >= 1) {
31+
return rtf.format(Math.round(hours), 'hour');
32+
}
33+
34+
if (Math.abs(minutes) >= 1) {
35+
return rtf.format(Math.round(minutes), 'minute');
36+
}
37+
38+
return rtf.format(Math.round(seconds), 'second');
39+
}

0 commit comments

Comments
 (0)