|
|
@ -1,116 +1,10 @@ |
|
|
|
'use strict'; |
|
|
|
import { format as _format, distanceInWordsToNow as _fromNow } from 'date-fns'; |
|
|
|
import * as en from 'date-fns/locale/en'; |
|
|
|
import * as dayjs from 'dayjs'; |
|
|
|
import * as advancedFormat from 'dayjs/plugin/advancedFormat'; |
|
|
|
import * as relativeTime from 'dayjs/plugin/relativeTime'; |
|
|
|
|
|
|
|
// Taken from https://github.com/date-fns/date-fns/blob/601bc8e5708cbaebee5389bdaf51c2b4b33b73c4/src/locale/en/build_distance_in_words_locale/index.js
|
|
|
|
function buildDistanceInWordsLocale() { |
|
|
|
const distanceInWordsLocale: { [key: string]: string | { one: string; other: string } } = { |
|
|
|
lessThanXSeconds: { |
|
|
|
one: 'less than a second', |
|
|
|
other: 'less than {{count}} seconds' |
|
|
|
}, |
|
|
|
|
|
|
|
xSeconds: { |
|
|
|
one: '1 second', |
|
|
|
other: '{{count}} seconds' |
|
|
|
}, |
|
|
|
|
|
|
|
halfAMinute: 'half a minute', |
|
|
|
|
|
|
|
lessThanXMinutes: { |
|
|
|
one: 'a few seconds', |
|
|
|
other: 'less than {{count}} minutes' |
|
|
|
}, |
|
|
|
|
|
|
|
xMinutes: { |
|
|
|
one: 'a minute', |
|
|
|
other: '{{count}} minutes' |
|
|
|
}, |
|
|
|
|
|
|
|
aboutXHours: { |
|
|
|
one: 'an hour', |
|
|
|
other: '{{count}} hours' |
|
|
|
}, |
|
|
|
|
|
|
|
xHours: { |
|
|
|
one: 'an hour', |
|
|
|
other: '{{count}} hours' |
|
|
|
}, |
|
|
|
|
|
|
|
xDays: { |
|
|
|
one: 'a day', |
|
|
|
other: '{{count}} days' |
|
|
|
}, |
|
|
|
|
|
|
|
aboutXMonths: { |
|
|
|
one: 'a month', |
|
|
|
other: '{{count}} months' |
|
|
|
}, |
|
|
|
|
|
|
|
xMonths: { |
|
|
|
one: 'a month', |
|
|
|
other: '{{count}} months' |
|
|
|
}, |
|
|
|
|
|
|
|
aboutXYears: { |
|
|
|
one: 'a year', |
|
|
|
other: '{{count}} years' |
|
|
|
}, |
|
|
|
|
|
|
|
xYears: { |
|
|
|
one: 'a year', |
|
|
|
other: '{{count}} years' |
|
|
|
}, |
|
|
|
|
|
|
|
overXYears: { |
|
|
|
one: 'a year', |
|
|
|
other: '{{count}} years' |
|
|
|
}, |
|
|
|
|
|
|
|
almostXYears: { |
|
|
|
one: 'a year', |
|
|
|
other: '{{count}} years' |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
function localize(token: string, count: number, options: any) { |
|
|
|
options = options || {}; |
|
|
|
|
|
|
|
if (count === 12 && token === 'xMonths') { |
|
|
|
token = 'aboutXYears'; |
|
|
|
count = 1; |
|
|
|
} |
|
|
|
|
|
|
|
const result = distanceInWordsLocale[token]; |
|
|
|
|
|
|
|
let value: string; |
|
|
|
if (typeof result === 'string') { |
|
|
|
value = result; |
|
|
|
} |
|
|
|
else if (count === 1) { |
|
|
|
value = result.one; |
|
|
|
} |
|
|
|
else { |
|
|
|
value = result.other.replace('{{count}}', count.toString()); |
|
|
|
} |
|
|
|
|
|
|
|
if (!options.addSuffix) return value; |
|
|
|
|
|
|
|
if (options.comparison > 0) return `in ${value}`; |
|
|
|
|
|
|
|
return `${value} ago`; |
|
|
|
} |
|
|
|
|
|
|
|
return { |
|
|
|
localize: localize |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
// Monkey patch the locale to customize the wording
|
|
|
|
const patch = en as any; |
|
|
|
patch.distanceInWords = buildDistanceInWordsLocale(); |
|
|
|
|
|
|
|
const formatterOptions = { addSuffix: true, locale: patch }; |
|
|
|
dayjs.extend(advancedFormat); |
|
|
|
dayjs.extend(relativeTime); |
|
|
|
|
|
|
|
export namespace Dates { |
|
|
|
export const MillisecondsPerMinute = 60000; // 60 * 1000
|
|
|
@ -122,28 +16,11 @@ export namespace Dates { |
|
|
|
format(format: string): string; |
|
|
|
} |
|
|
|
|
|
|
|
export function dateDaysFromNow(date: Date, now: number = Date.now()) { |
|
|
|
const startOfDayLeft = startOfDay(now); |
|
|
|
const startOfDayRight = startOfDay(date); |
|
|
|
|
|
|
|
const timestampLeft = startOfDayLeft.getTime() - startOfDayLeft.getTimezoneOffset() * MillisecondsPerMinute; |
|
|
|
const timestampRight = startOfDayRight.getTime() - startOfDayRight.getTimezoneOffset() * MillisecondsPerMinute; |
|
|
|
|
|
|
|
return Math.round((timestampLeft - timestampRight) / MillisecondsPerDay); |
|
|
|
} |
|
|
|
|
|
|
|
export function startOfDay(date: Date | number) { |
|
|
|
const newDate = new Date(typeof date === 'number' ? date : date.getTime()); |
|
|
|
newDate.setHours(0, 0, 0, 0); |
|
|
|
return newDate; |
|
|
|
} |
|
|
|
|
|
|
|
export function toFormatter(date: Date): DateFormatter { |
|
|
|
const wrappedDate = dayjs(date); |
|
|
|
return { |
|
|
|
fromNow: () => { |
|
|
|
return _fromNow(date, formatterOptions); |
|
|
|
}, |
|
|
|
format: (format: string) => _format(date, format) |
|
|
|
fromNow: () => wrappedDate.fromNow(), |
|
|
|
format: (format: string) => wrappedDate.format(format) |
|
|
|
}; |
|
|
|
} |
|
|
|
} |