An error occurred while rendering the visualization: TypeError: o.getTime is not a function
Bug description
Given this table visualization with time comparison enabled:
When I click on the date column header to sort data by date (column is a TIMESTAMP in Postgres), I receive this error:
How to reproduce the bug
- Create table visualization with datetime dimension
- Add Time comparison
- Click on datetime header to sort data
Screenshots/recordings
No response
Superset version
master / latest-dev
Python version
3.9
Node version
16
Browser
Chrome
Additional context
Using docker image superset:e8f5d76-dev
Checklist
- [X] I have searched Superset docs and Slack and didn't find a solution to my problem.
- [X] I have searched the GitHub issue tracker and didn't find a similar bug report.
- [ ] I have checked Superset's logs for errors and if I found a relevant Python stacktrace, I included it here as text in the "additional context" section.
@ilvenini Hello there! I'm a bot designed to help you with bug fixes, answer questions, and guide you on becoming a contributor. I'm here to assist you while waiting for a human maintainer.
To resolve the "TypeError: o.getTime is not a function" error when sorting a datetime column in a table visualization with time comparison enabled in Superset, ensure that the datetime values being processed are correctly parsed into Date objects. The error typically occurs when a non-date value is passed to a function expecting a Date object.
In the provided code, the parseDttmToDate function is responsible for converting datetime strings into Date objects. Ensure that this function is correctly used to parse all datetime values before any operations that require Date objects.
Here is an example of how you can use the parseDttmToDate function to ensure datetime values are correctly parsed:
const parsedDate = parseDttmToDate(dttmString);
if (parsedDate && !Number.isNaN(parsedDate.getTime())) {
// Proceed with operations that require a Date object
} else {
// Handle the case where the datetime string could not be parsed
console.error("Invalid datetime string:", dttmString);
}
In the getTimeOffset function, ensure that the parseDttmToDate function is used to parse the startStr and endStr values:
const [startStr, endStr] = (timeRangeFilter?.comparator ?? '')
.split(' : ')
.map((date: string) => date.trim());
const filterStartDateTime = (parseDttmToDate(startStr, false, false))?.getTime() || 0;
const filterEndDateTime = (parseDttmToDate(endStr || startStr, true, false))?.getTime() || 0;
Additionally, ensure that datetime values are correctly processed in the processDataRecords function. This function converts datetime values into a custom DateWithFormatter class, which allows for proper sorting and formatting:
const processDataRecords = memoizeOne(function processDataRecords(
data: DataRecord[] | undefined,
columns: DataColumnMeta[],
) {
if (!data?.[0]) {
return data || [];
}
const timeColumns = columns.filter(
column => column.dataType === GenericDataType.Temporal,
);
if (timeColumns.length > 0) {
return data.map(x => {
const datum = { ...x };
timeColumns.forEach(({ key, formatter }) => {
// Convert datetime with a custom date class so we can use `String(...)`
// formatted value for global search, and `date.getTime()` for sorting.
datum[key] = new DateWithFormatter(x[key], {
formatter: formatter as TimeFormatter,
});
});
return datum;
});
}
return data;
});
In the buildQuery function, ensure that the getTimeOffset function is correctly used to handle time comparisons:
const timeOffsets = ensureIsArray(
isTimeComparison(formData, baseQueryObject)
? getTimeOffset({
timeRangeFilter: {
...TimeRangeFilters[0],
comparator:
baseQueryObject?.time_range ??
(TimeRangeFilters[0] as any)?.comparator,
},
shifts: formData.time_compare,
startDate:
previousCustomStartDate && !formData.start_date_offset
? parseDttmToDate(previousCustomStartDate)?.toUTCString()
: formData.start_date_offset,
})
: [],
);
In the TimeTable component, ensure that datetime values are correctly processed and sorted. The sortNumberWithMixedTypes function is used to handle sorting of numeric values, including datetime values:
const sortNumberWithMixedTypes = (rowA, rowB, columnId, descending) =>
sortNumericValues(
rowA.values[columnId].props['data-value'],
rowB.values[columnId].props['data-value'],
{ descending, nanTreatment: 'asSmallest' },
) *
// react-table sort function always expects -1 for smaller number
(descending ? -1 : 1);
By ensuring that all datetime strings are correctly parsed into Date objects and processed appropriately, you can avoid the "TypeError: o.getTime is not a function" error [1][2][3][4].
To continue talking to Dosu, mention @dosu.
We also encounter this bug,
the workaround is to convert the date value to string at the SQL level
eg: TO_CHAR(date_column, 'YYYY-MM-DD')
This has been silent for 200+ days, and I think the last comment is the correct answer... cast dates to the correct format, and all should be well.
This workaround did not work: TO_CHAR(date_column, 'YYYY-MM-DD'). Seems like a fix would make superset easier to use.