@technobuddha/library
Version:
A large library of useful functions
106 lines (97 loc) • 3.15 kB
text/typescript
import { addTime } from './add-time.ts';
import { secondsPerDay, secondsPerHour, secondsPerMinute, ticksPerSecond } from './date.ts';
import { floor } from './floor.ts';
import { formatDate } from './format-date.ts';
import { isSameDay } from './is-same-day.ts';
import { plural } from './plural.ts';
import { space } from './unicode.ts';
/**
* Options for the {@link relativeTime} function
* @group Time
* @category Relative Time
*/
export type RelativeTimeOptions = {
/** Describe the time difference as a time on a nearby day */
todayTomorrowYesterday?: boolean;
/** Passed to {@link formatDate} to display a time */
timeFormat?: string;
/** Passed to {@link formatDate} to display a year, month and day */
ymdFormat?: string;
/** Passed to {@link formatDate} to display a month and day */
mdFormat?: string;
};
/**
* Describe the difference between two dates in a simple format
* @param input - The date
* @param relativeTo - The date to compare to
* @param options - see {@link RelativeTimeOptions}
* @returns string describing the time difference between the two dates
* @group Time
* @category Relative Time
*/
export function relativeTime(
input: Date,
relativeTo: Date,
{
todayTomorrowYesterday = false,
timeFormat = 'H:mm TT',
ymdFormat = 'MMMM D YYYY',
mdFormat = 'MMMM D',
}: RelativeTimeOptions = {},
): string {
const text = [] as string[];
if (todayTomorrowYesterday) {
if (isSameDay(input, relativeTo)) {
text.push(`today ${formatDate(input, timeFormat)} -`);
} else if (isSameDay(input, addTime(relativeTo, { days: 1 }))) {
text.push(`tomorrow ${formatDate(input, timeFormat)} -`);
} else if (isSameDay(input, addTime(relativeTo, { days: -1 }))) {
text.push(`yesterday ${formatDate(input, timeFormat)} -`);
}
}
let diff = (input.getTime() - relativeTo.getTime()) / ticksPerSecond;
let sign = 1;
if (diff < 0) {
sign = -1;
diff = Math.abs(diff);
}
const d = floor(diff / secondsPerDay, { tolerance: 0.05 });
const h = floor((diff - d * secondsPerDay) / secondsPerHour, { tolerance: 0.05 });
const m = floor((diff - d * secondsPerDay - h * secondsPerHour) / secondsPerMinute, {
tolerance: 0.05,
});
const s = floor(diff - d * secondsPerDay - h * secondsPerHour - m * secondsPerMinute, {
tolerance: 0.05,
});
if (d > 90) {
text.push(formatDate(input, ymdFormat));
sign = 0;
} else if (d > 30) {
text.push(formatDate(input, mdFormat));
sign = 0;
} else if (d > 0) {
text.push(plural('day', d, true));
if (d < 4 && h > 1) {
text.push(plural('hour', h, true));
}
} else if (h > 0) {
text.push(plural('hour', h, true));
if (h < 4 && m > 0) {
text.push(plural('minute', m, true));
}
} else if (m > 0) {
text.push(plural('minute', m, true));
if (m < 4 && s > 0) {
text.push(plural('second', s, true));
}
} else if (s > 0) {
text.push(plural('second', s, true));
}
if (sign === -1) {
text.push('ago');
}
if (sign === 1) {
text.push(d || h || m || s ? 'from now' : 'now');
}
return text.join(space);
}