import {parseUTCDate, formatMonthYYYY, formatDayShort} from '../../util/date' const browserDateFormat = Intl.DateTimeFormat(navigator.language, { hour: 'numeric' }) const is12HourClock = function () { return browserDateFormat.resolvedOptions().hour12 } const monthIntervalFormatter = { long(isoDate, options) { const formatted = this.short(isoDate, options) return options.isBucketPartial ? `Partial of ${formatted}` : formatted }, short(isoDate, _options) { return formatMonthYYYY(parseUTCDate(isoDate)) } } const weekIntervalFormatter = { long(isoDate, options) { const formatted = this.short(isoDate, options) return options.isBucketPartial ? `Partial week of ${formatted}` : `Week of ${formatted}` }, short(isoDate, options) { return formatDayShort(parseUTCDate(isoDate), options.shouldShowYear) } } const dateIntervalFormatter = { long(isoDate, _options) { return parseUTCDate(isoDate).format('ddd, D MMM') }, short(isoDate, options) { return formatDayShort(parseUTCDate(isoDate), options.shouldShowYear) } } const hourIntervalFormatter = { long(isoDate, options) { return this.short(isoDate, options) }, short(isoDate, _options) { if (is12HourClock()) { return parseUTCDate(isoDate).format('ha') } else { return parseUTCDate(isoDate).format('HH:mm') } } } const minuteIntervalFormatter = { long(isoDate, options) { if (options.period == 'realtime') { const minutesAgo = Math.abs(isoDate) return minutesAgo === 1 ? '1 minute ago' : minutesAgo + ' minutes ago' } else { return this.short(isoDate, options) } }, short(isoDate, options) { if (options.period === 'realtime') return isoDate + 'm' if (is12HourClock()) { return parseUTCDate(isoDate).format('h:mma') } else { return parseUTCDate(isoDate).format('HH:mm') } } } // Each interval has a different date and time format. This object maps each // interval with two functions: `long` and `short`, that formats date and time // accordingly. const factory = { month: monthIntervalFormatter, week: weekIntervalFormatter, date: dateIntervalFormatter, hour: hourIntervalFormatter, minute: minuteIntervalFormatter } /** * Returns a function that formats a ISO 8601 timestamp based on the given * arguments. * * The preferred date and time format in the dashboard depends on the selected * interval and period. For example, in real-time view only the time is necessary, * while other intervals require dates to be displayed. * @param {Object} config - Configuration object for determining formatter. * * @param {string} config.interval - The interval of the query, e.g. `minute`, `hour` * @param {boolean} config.longForm - Whether the formatted result should be in long or * short form. * @param {string} config.period - The period of the query, e.g. `12mo`, `day` * @param {boolean} config.isPeriodFull - Indicates whether the interval has been cut * off by the requested date range or not. If false, the returned formatted date * indicates this cut off, e.g. `Partial week of November 8`. * @param {boolean} config.shouldShowYear - Should the year be appended to the date? * Defaults to false. Rendering year string is a newer opt-in feature to be enabled where needed. */ export default function dateFormatter({ interval, longForm, period, isPeriodFull, shouldShowYear = false }) { const displayMode = longForm ? 'long' : 'short' const options = { period: period, interval: interval, isBucketPartial: !isPeriodFull, shouldShowYear } return function (isoDate, _index, _ticks) { return factory[interval][displayMode](isoDate, options) } }