From 8484b4300196426f1af6e4f237a03fa35208face Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Thu, 7 Nov 2019 00:08:25 -0800 Subject: [PATCH] DisplayProcessor: improve time field support (#20223) --- .../src/datetime/moment_wrapper.ts | 9 ---- .../src/field/displayProcessor.test.ts | 36 ++++++++++++++ .../src/field/displayProcessor.ts | 47 +++++++++++++------ 3 files changed, 68 insertions(+), 24 deletions(-) diff --git a/packages/grafana-data/src/datetime/moment_wrapper.ts b/packages/grafana-data/src/datetime/moment_wrapper.ts index c2ddeae3da0..32e58f80ca5 100644 --- a/packages/grafana-data/src/datetime/moment_wrapper.ts +++ b/packages/grafana-data/src/datetime/moment_wrapper.ts @@ -1,7 +1,6 @@ import { TimeZone } from '../types/time'; /* tslint:disable:import-blacklist ban ban-types */ import moment, { Moment, MomentInput, DurationInputArg1 } from 'moment'; -import { DEFAULT_DATE_TIME_FORMAT } from './formats'; export interface DateTimeBuiltinFormat { __momentBuiltinFormatBrand: any; } @@ -38,7 +37,6 @@ export type DurationUnit = | 'quarters' | 'Q'; -export type DateFormatter = (date: DateTimeInput, format?: string) => string; export interface DateTimeLocale { firstDayOfWeek: () => number; } @@ -115,10 +113,3 @@ export const dateTimeForTimeZone = ( return dateTime(input, formatInput); }; - -export const getTimeZoneDateFormatter: (timezone?: TimeZone) => DateFormatter = timezone => (date, format) => { - date = isDateTime(date) ? date : dateTime(date); - format = format || DEFAULT_DATE_TIME_FORMAT; - - return timezone === 'browser' ? dateTime(date).format(format) : toUtc(date).format(format); -}; diff --git a/packages/grafana-data/src/field/displayProcessor.test.ts b/packages/grafana-data/src/field/displayProcessor.test.ts index 67e0f953808..ed1417ea109 100644 --- a/packages/grafana-data/src/field/displayProcessor.test.ts +++ b/packages/grafana-data/src/field/displayProcessor.test.ts @@ -1,6 +1,7 @@ import { getDisplayProcessor, getColorFromThreshold } from './displayProcessor'; import { DisplayProcessor, DisplayValue } from '../types/displayValue'; import { ValueMapping, MappingType } from '../types/valueMapping'; +import { FieldType } from '../types'; function assertSame(input: any, processors: DisplayProcessor[], match: DisplayValue) { processors.forEach(processor => { @@ -192,3 +193,38 @@ describe('Format value', () => { expect(instance(value).text).toEqual('1.000 Mil'); }); }); + +describe('Date display options', () => { + it('should format UTC dates', () => { + const processor = getDisplayProcessor({ + type: FieldType.time, + isUtc: true, + config: { + unit: 'xyz', // ignore non-date formats + }, + }); + expect(processor(0).text).toEqual('1970-01-01 00:00:00'); + }); + + it('should pick configured time format', () => { + const processor = getDisplayProcessor({ + type: FieldType.time, + isUtc: true, + config: { + unit: 'dateTimeAsUS', // A configurable date format + }, + }); + expect(processor(0).text).toEqual('01/01/1970 12:00:00 am'); + }); + + it('respect the configured date format', () => { + const processor = getDisplayProcessor({ + type: FieldType.time, + isUtc: true, + config: { + dateDisplayFormat: 'YYYY', + }, + }); + expect(processor(0).text).toEqual('1970'); + }); +}); diff --git a/packages/grafana-data/src/field/displayProcessor.ts b/packages/grafana-data/src/field/displayProcessor.ts index e27511f2fde..d169cb39cfd 100644 --- a/packages/grafana-data/src/field/displayProcessor.ts +++ b/packages/grafana-data/src/field/displayProcessor.ts @@ -11,8 +11,8 @@ import { DisplayProcessor, DisplayValue, DecimalCount, DecimalInfo } from '../ty import { getValueFormat } from '../valueFormats/valueFormats'; import { getMappedValue } from '../utils/valueMappings'; import { Threshold } from '../types/threshold'; -import { getTimeZoneDateFormatter } from '../datetime/moment_wrapper'; -import { DEFAULT_DATE_TIME_FORMAT } from '../datetime'; +import { DateTime, DEFAULT_DATE_TIME_FORMAT, isDateTime, dateTime, toUtc } from '../datetime'; +import { KeyValue } from '../types'; interface DisplayProcessorOptions { type?: FieldType; @@ -23,22 +23,39 @@ interface DisplayProcessorOptions { theme?: GrafanaTheme; // Will pick 'dark' if not defined } +// Reasonable units for time +const timeFormats: KeyValue = { + dateTimeAsIso: true, + dateTimeAsUS: true, + dateTimeFromNow: true, +}; + export function getDisplayProcessor(options?: DisplayProcessorOptions): DisplayProcessor { if (options && !_.isEmpty(options)) { - if (options.type && options.type === FieldType.time) { - return (value: any) => { - let dateFormat = DEFAULT_DATE_TIME_FORMAT; - if (options.config && options.config.dateDisplayFormat) { - dateFormat = options.config.dateDisplayFormat; - } - const formatedDate = getTimeZoneDateFormatter(options.isUtc ? 'utc' : 'browser')(value, dateFormat); - return { - numeric: value, - text: formatedDate, - }; - }; - } const field = options.config ? options.config : {}; + + if (options.type === FieldType.time) { + if (field.unit && timeFormats[field.unit]) { + // Currently selected unit is valid for time fields + } else { + const dateFormat = field.dateDisplayFormat || DEFAULT_DATE_TIME_FORMAT; + + // UTC or browser based timezone + let fmt = (date: DateTime) => date.format(dateFormat); + if (options.isUtc) { + fmt = (date: DateTime) => toUtc(date).format(dateFormat); + } + + return (value: any) => { + const date: DateTime = isDateTime(value) ? value : dateTime(value); + return { + numeric: isNaN(value) ? date.valueOf() : value, + text: fmt(date), + }; + }; + } + } + const formatFunc = getValueFormat(field.unit || 'none'); return (value: any) => {