diff --git a/packages/grafana-data/src/transformations/transformers/convertFieldType.test.ts b/packages/grafana-data/src/transformations/transformers/convertFieldType.test.ts index 15dfed729c8..a41e61f556f 100644 --- a/packages/grafana-data/src/transformations/transformers/convertFieldType.test.ts +++ b/packages/grafana-data/src/transformations/transformers/convertFieldType.test.ts @@ -486,4 +486,52 @@ describe('fieldToTimeField', () => { ], }); }); + + it('should properly parse Unix timestamps - in seconds', () => { + const numberTimeField: Field = { + config: {}, + name: 'Unix second timestamps', + type: FieldType.number, + values: [1728397800, 1728397815, 1728397830], + }; + + expect(fieldToTimeField(numberTimeField, 'X')).toEqual({ + config: {}, + name: 'Unix second timestamps', + type: FieldType.time, + values: [1728397800000, 1728397815000, 1728397830000], + }); + }); + + it('should properly parse Unix timestamps - in millseconds (with format)', () => { + const numberTimeField: Field = { + config: {}, + name: 'Unix MS timestamps', + type: FieldType.number, + values: [1728397800000, 1728397815000, 1728397830000], + }; + + expect(fieldToTimeField(numberTimeField, 'x')).toEqual({ + config: {}, + name: 'Unix MS timestamps', + type: FieldType.time, + values: [1728397800000, 1728397815000, 1728397830000], + }); + }); + + it('should properly parse Unix timestamps - in millseconds (without format)', () => { + const numberTimeField: Field = { + config: {}, + name: 'Unix MS timestamps', + type: FieldType.number, + values: [1728397800000, 1728397815000, 1728397830000], + }; + + expect(fieldToTimeField(numberTimeField)).toEqual({ + config: {}, + name: 'Unix MS timestamps', + type: FieldType.time, + values: [1728397800000, 1728397815000, 1728397830000], + }); + }); }); diff --git a/packages/grafana-data/src/transformations/transformers/convertFieldType.ts b/packages/grafana-data/src/transformations/transformers/convertFieldType.ts index 7eda28e04f5..3b3967a68b5 100644 --- a/packages/grafana-data/src/transformations/transformers/convertFieldType.ts +++ b/packages/grafana-data/src/transformations/transformers/convertFieldType.ts @@ -131,13 +131,17 @@ export function fieldToTimeField(field: Field, dateFormat?: string): Field { const timeValues = field.values.slice(); let firstDefined = timeValues.find((v) => v != null); - - let isISO8601 = typeof firstDefined === 'string' && iso8601Regex.test(firstDefined); + const convertToMS = typeof firstDefined === 'number' && dateFormat === 'X'; + const isISO8601 = typeof firstDefined === 'string' && iso8601Regex.test(firstDefined); for (let t = 0; t < timeValues.length; t++) { if (timeValues[t]) { let parsed = isISO8601 ? Date.parse(timeValues[t]) : dateTimeParse(timeValues[t], opts).valueOf(); - timeValues[t] = Number.isFinite(parsed) ? parsed : null; + if (Number.isFinite(parsed)) { + timeValues[t] = convertToMS ? parsed * 1000 : parsed; + } else { + timeValues[t] = null; + } } else { timeValues[t] = null; } @@ -254,10 +258,13 @@ function fieldToComplexField(field: Field): Field { */ export function ensureTimeField(field: Field, dateFormat?: string): Field { const firstValueTypeIsNumber = typeof field.values[0] === 'number'; + // if the format is unix seconds, we don't want to skip formatting + const isUnixSecondsFormat = dateFormat === 'X'; + if (field.type === FieldType.time && firstValueTypeIsNumber) { return field; //already time } - if (firstValueTypeIsNumber) { + if (firstValueTypeIsNumber && !isUnixSecondsFormat) { return { ...field, type: FieldType.time, //assumes it should be time