Skip to content

Conversation

@aarya-16
Copy link

@aarya-16 aarya-16 commented Oct 5, 2025

This PR fixes #211 and implements user-selectable timestamp formatting for chart panel X-axis labels in the QuestDB Web Console, addressing the need for multiple timestamp display formats when visualizing time-series data.

Changes Made

Core Files Modified:

  • packages/web-console/src/js/console/quick-vis.ts - Added timestamp formatting logic
  • packages/web-console/src/scenes/Result/index.tsx - Added time format selector UI
  • packages/web-console/src/styles/_quick-vis.scss - Added styling for format controls

New Features

  1. Smart Time Column Detection: Automatically identifies timestamp columns in query results

  2. 7 Format Options: User can select from:

    • Auto (intelligent format based on data patterns)
    • yyyy-MM-dd HH:mm:ss (full datetime)
    • HH:mm:ss (time with seconds)
    • HH:mm (time without seconds)
    • MM/dd HH:mm (US date format)
    • MMM dd yyyy (readable date)
    • Relative (human-readable, e.g., "1h ago, 15d ago")
  3. Real-time Chart Updates: Chart re-renders immediately when format changes

Technical Implementation

  • Time Detection: detectTimeColumns() function identifies TIMESTAMP columns and time-related field names
  • Format Engine: formatTimestamp() with precise formatting
  • Auto-Detection: autoDetectTimeFormat() intelligently selects format based on data age
  • ECharts Integration: Enhanced X-axis configuration with dynamic label formatting
  • UI Controls: Dropdown selector with smooth transitions and dark theme compatibility
Screen.Recording.2025-10-05.205830.mp4

@CLAassistant
Copy link

CLAassistant commented Oct 5, 2025

CLA assistant check
All committers have signed the CLA.

@aarya-16
Copy link
Author

aarya-16 commented Oct 5, 2025

@emrberk Please take a look and review this.

// Detect timestamp columns by type or name patterns
return col.type === 'TIMESTAMP' ||
col.type === 'TIMESTAMP_NS' ||
/timestamp|time|date|created|updated/i.test(col.name)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot rely on column name for detecting the timestamp. Types are already enough for this purpose. We have an utility function in ImportCSVFiles, so you can move it to src/utils/... and use it here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll work on this.

const parsed = Date.parse(value)
return !isNaN(parsed) && parsed > 0
}
if (typeof value === 'number') {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In which cases does QuestDB return a number for a timestamp column? Why do we have this check?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the time is stored in milliseconds since epoch for example.

date = new Date(timestamp)
} else if (typeof timestamp === 'number') {
date = new Date(timestamp)
} else {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which case is covered in this branch? Can you give an example?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you are asking about number, then like before it could be the milliseconds type. Or an ISO Format String.

return timestamp.toString()
}

if (isNaN(date.getTime())) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which case is covered in this branch? Can you give an example?

// Helper function to pad numbers with leading zeros
const pad = (num: number): string => num.toString().padStart(2, '0')

switch (format) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have date-fns dependency and it provides useful functions for this purpose.
This one can be replaced with format function from that package.

return `${Math.floor(absDiff/86400000)}d ago`
}

function autoDetectTimeFormat(timestamp: number): string {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue, use date-fns.

function formatRelativeTime(timestamp: number): string {
const now = new Date().getTime()
const diff = now - timestamp
const absDiff = Math.abs(diff)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which case do we cover with abs call?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An edge case where future timestamps may be stored in a table. Like forecasts, for example.

// Time format picker options
const timeFormatOptions = [
{ text: "Auto", value: "auto" },
{ text: "2021-11-21 14:04:09", value: "yyyy-MM-dd HH:mm:ss" },
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The value string is explicit enough so that we can use it in text as well. These numbers are arbitrary.


// Event listener for X-axis selection to toggle time format visibility
xAxisPicker.onChange = (info: any) => {
if (cachedResponse && cachedResponse.columns) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Time format picker is shown in the first render regardless of the contents of the x-axis and y-axis elements.
If you remove timestamp from x-axis, then the picker visibility is not responsive.
If you rely on the cached response, the visibility will depend on the previous draw, which is not expected.

btnDraw.click(btnDrawClick)

// Event listener for X-axis selection to toggle time format visibility
xAxisPicker.onChange = (info: any) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if i specify a format from format picker, and include a timestamp column in y-axis?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The timestamp values will be displayed as data points.

@aarya-16 aarya-16 requested a review from emrberk October 31, 2025 18:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Timestamp formatting in Chart Panel should be configurable

3 participants