Dashboards & Visualizations

Does Dashboard Studio force time-like string to not be string type?

yuanliu
SplunkTrust
SplunkTrust

I first notice that Dashboard Studio's input configuration UI sometimes treats a time string as "number"; as a result, that input would not even be populated.  I had to use tostring or another trick to force the UI to accept it as string.

After trying for two days, I haven't been able to reproduce the "number" scenario with trivial data.  With trivial data, DS's configuration UI always treats a time string as "time" (as opposed to "string") unless otherwise forced.  In addition to strange effects in input selector (see example below), DS also passes token of type "time" in a specific format that may be different from the original string.  This may also be undesired.

Here is a sample dashboard to illustrate this.  Source data:

timestring_value
2026-01-23 11:44:252026-01-23 11:44:25
2026-01-23 11:44:252026-01-23 11:44:25
2026-01-27 11:44:252026-01-27 11:44:25
2026-01-27 11:44:252026-01-27 11:44:25
2026-01-27 11:44:252026-01-27 11:44:25
2026-01-29 11:44:252026-01-29 11:44:25
2026-01-30 11:44:252026-01-30 11:44:25
2026-01-30 11:44:252026-01-30 11:44:25
2026-01-31 11:44:252026-01-31 11:44:25
2026-01-31 11:44:252026-01-31 11:44:25
2026-01-31 11:44:252026-01-31 11:44:25

As shown, timestring is of format "%F %T", which a white space between date and time.  The idea is to use the date part as label and pass the timestring as token value.  For this, I tried several ways to obtain single-value timestring such as values() stats function, max() stats function, groupby timestring, and mvexpand timestring.  I also tried different ways to obtain label from timestring including using rex command and using replace function.  To make values very clear in each case, I use top panels to show output from respective searches for the token; these outputs include an evaluation of type of timestring and label to verify that Splunk search shows all of them as String.  The bottom panels simply displays the token value as passed by Dashboard Studio.  As shown, all these token values are transformed into "%FT%T", i.e., with letter "T" between date and time.

 

{
    "title": "Dashboard Studio thinks time string is other than string",
    "description": "",
    "inputs": {
        "input_1kIxDHKk": {
            "context": {
                "formattedConfig": {
                    "number": {
                        "prefix": ""
                    }
                },
                "formattedStatics": ">statics | formatByType(formattedConfig)",
                "label": ">primary | seriesByName(\"label\") | renameSeries(\"label\") | formatByType(formattedConfig)",
                "statics": [],
                "value": ">primary | seriesByName(\"timestring\") | renameSeries(\"value\") | formatByType(formattedConfig)"
            },
            "dataSources": {
                "primary": "ds_Uh3WYGcG"
            },
            "options": {
                "items": ">frame(label, value) | prepend(formattedStatics) | objects()",
                "selectFirstSearchResult": true,
                "token": "groupby_rex_tok"
            },
            "title": "groupby with rex label",
            "type": "input.dropdown"
        },
        "input_2qavhtpJ": {
            "context": {
                "formattedConfig": {
                    "number": {
                        "prefix": ""
                    }
                },
                "formattedStatics": ">statics | formatByType(formattedConfig)",
                "label": ">primary | seriesByName(\"timestring\") | renameSeries(\"label\") | formatByType(formattedConfig)",
                "statics": [],
                "value": ">primary | seriesByName(\"timestring\") | renameSeries(\"value\") | formatByType(formattedConfig)"
            },
            "dataSources": {
                "primary": "ds_GAZj9qSN"
            },
            "options": {
                "items": ">frame(label, value) | prepend(formattedStatics) | objects()",
                "selectFirstSearchResult": true,
                "token": "max_timestring_tok"
            },
            "title": "max timestring",
            "type": "input.dropdown"
        },
        "input_R3Q1RvBK": {
            "context": {
                "formattedConfig": {
                    "number": {
                        "prefix": ""
                    }
                },
                "formattedStatics": ">statics | formatByType(formattedConfig)",
                "label": ">primary | seriesByName(\"label\") | renameSeries(\"label\") | formatByType(formattedConfig)",
                "statics": [],
                "value": ">primary | seriesByName(\"timestring\") | renameSeries(\"value\") | formatByType(formattedConfig)"
            },
            "dataSources": {
                "primary": "ds_nZMqnAeL"
            },
            "options": {
                "items": ">frame(label, value) | prepend(formattedStatics) | objects()",
                "selectFirstSearchResult": true,
                "token": "mvexpand_rex_tok"
            },
            "title": "mvexpand with rex label",
            "type": "input.dropdown"
        },
        "input_qjIV5Ix1": {
            "context": {
                "formattedConfig": {
                    "number": {
                        "prefix": ""
                    }
                },
                "formattedStatics": ">statics | formatByType(formattedConfig)",
                "label": ">primary | seriesByName(\"label\") | renameSeries(\"label\") | formatByType(formattedConfig)",
                "statics": [],
                "value": ">primary | seriesByName(\"timestring\") | renameSeries(\"value\") | formatByType(formattedConfig)"
            },
            "dataSources": {
                "primary": "ds_beX8QYoY"
            },
            "options": {
                "items": ">frame(label, value) | prepend(formattedStatics) | objects()",
                "selectFirstSearchResult": true,
                "token": "label_replace_tok"
            },
            "title": "label by replace",
            "type": "input.dropdown"
        }
    },
    "defaults": {
        "dataSources": {
            "ds.search": {
                "options": {
                    "queryParameters": {
                        "earliest": "$global_time.earliest$",
                        "latest": "$global_time.latest$"
                    }
                }
            }
        },
        "visualizations": {
            "global": {
                "showProgressBar": true
            }
        }
    },
    "visualizations": {
        "viz_93ySZ5Cc": {
            "dataSources": {
                "primary": "ds_Uh3WYGcG"
            },
            "description": "| stats count as _count by timestring | rex field=timestring \"(?<label>\\S+)\" | sort - label | eval v_type = typeof(timestring), l_type = typeof(label) | fields label l_type timestring v_type",
            "options": {
                "columnFormat": {
                    "l_type": {
                        "width": 84
                    },
                    "label": {
                        "width": 86
                    },
                    "timestring": {
                        "width": 136
                    }
                },
                "showInternalFields": false
            },
            "title": "groupby with rex label",
            "type": "splunk.table"
        },
        "viz_HaKyhXKv": {
            "dataSources": {
                "primary": "ds_sfp5IIKQ"
            },
            "type": "splunk.table"
        },
        "viz_KJJE0cri": {
            "dataSources": {
                "primary": "ds_GAZj9qSN"
            },
            "description": "| stats max(timestring) as timestring by _value | eval v_type = typeof(timestring) | sort - timestring",
            "options": {
                "columnFormat": {
                    "timestring": {
                        "width": 127
                    }
                },
                "showInternalFields": false
            },
            "title": "max timestring",
            "type": "splunk.table"
        },
        "viz_SMBNQ4XA": {
            "dataSources": {
                "primary": "ds_nZMqnAeL"
            },
            "description": "| stats values(timestring) as timestring | mvexpand timestring | rex field=timestring \"(?<label>\\S+)\" | eval v_type = typeof(timestring), l_type = typeof(label) | sort - label | fields label l_type timestring v_type",
            "options": {
                "columnFormat": {
                    "label": {
                        "width": 98
                    },
                    "timestring": {
                        "width": 158
                    }
                },
                "showInternalFields": false
            },
            "title": "mvexpand with rex label",
            "type": "splunk.table"
        },
        "viz_UsOo59WW": {
            "dataSources": {
                "primary": "ds_beX8QYoY"
            },
            "description": "| stats values(timestring) as timestring by _value | rex field=timestring \"(?<label>\\S+)\" | eval v_type = typeof(timestring), l_type = typeof(label) | sort - label | fields label l_type timestring v_type",
            "options": {
                "columnFormat": {
                    "l_type": {
                        "width": 93
                    },
                    "label": {
                        "width": 108
                    },
                    "timestring": {
                        "width": 147
                    }
                },
                "showInternalFields": false
            },
            "title": "label by replace",
            "type": "splunk.table"
        },
        "viz_amq7ntem": {
            "containerOptions": {},
            "dataSources": {
                "primary": "ds_lWSFXLao"
            },
            "options": {
                "columnFormat": {
                    "max_timestring_tok": {
                        "width": 190
                    }
                }
            },
            "showLastUpdated": false,
            "showProgressBar": true,
            "type": "splunk.table"
        },
        "viz_bMEWY9PX": {
            "dataSources": {
                "primary": "ds_z6WkSe6U"
            },
            "options": {
                "columnFormat": {
                    "label_replace_tok": {
                        "width": 90
                    }
                }
            },
            "type": "splunk.table"
        },
        "viz_dvN9WkEw": {
            "dataSources": {
                "primary": "ds_Nwgz464R"
            },
            "options": {
                "showInternalFields": false
            },
            "type": "splunk.table"
        }
    },
    "dataSources": {
        "ds_34OFi4Mu": {
            "name": "multivalue timestring",
            "options": {
                "query": "| makeresults format=csv data=\"timestring\n2026-01-23 11:44:25\n2026-01-23 11:44:25\n2026-01-27 11:44:25\n2026-01-27 11:44:25\n2026-01-27 11:44:25\n2026-01-29 11:44:25\n2026-01-30 11:44:25\n2026-01-30 11:44:25\n2026-01-31 11:44:25\n2026-01-31 11:44:25\n2026-01-31 11:44:25\"\n| eval _value = timestring\n",
                "queryParameters": {
                    "earliest": "-24h@h",
                    "latest": "now"
                }
            },
            "type": "ds.search"
        },
        "ds_GAZj9qSN": {
            "name": "max timestring",
            "options": {
                "extend": "ds_34OFi4Mu",
                "query": "| stats max(timestring) as timestring by _value\n| eval v_type = typeof(timestring)\n| sort - timestring"
            },
            "type": "ds.chain"
        },
        "ds_Nwgz464R": {
            "name": "timestring as groupby passed",
            "options": {
                "query": "| makeresults format=csv data=\"groupby_rex_tok\n$groupby_rex_tok$\"\n| eval type = typeof(groupby_rex_tok)",
                "queryParameters": {
                    "earliest": "-24h@h",
                    "latest": "now"
                }
            },
            "type": "ds.search"
        },
        "ds_Uh3WYGcG": {
            "name": "timestring as groupby",
            "options": {
                "extend": "ds_34OFi4Mu",
                "query": "| stats count as _count by timestring\n| rex field=timestring \"(?<label>\\S+)\"\n| sort - label\n| eval v_type = typeof(timestring), l_type = typeof(label)\n| fields label l_type timestring v_type"
            },
            "type": "ds.chain"
        },
        "ds_beX8QYoY": {
            "name": "label from replace",
            "options": {
                "extend": "ds_34OFi4Mu",
                "query": "| stats values(timestring) as timestring by _value\n| eval label=replace(timestring, \"(\\S+).+\", \"\\1\")\n| eval v_type = typeof(timestring), l_type = typeof(label)\n| sort - label\n| fields label l_type timestring v_type"
            },
            "type": "ds.chain"
        },
        "ds_lWSFXLao": {
            "name": "time string passed",
            "options": {
                "query": "| makeresults format=csv data=\"max_timestring_tok\n$max_timestring_tok$\"\n| eval type = typeof(max_timestring_tok)",
                "queryParameters": {
                    "earliest": "-24h@h",
                    "latest": "now"
                }
            },
            "type": "ds.search"
        },
        "ds_nZMqnAeL": {
            "name": "mvexpand with rex label",
            "options": {
                "extend": "ds_34OFi4Mu",
                "query": "| stats values(timestring) as timestring\n| mvexpand timestring\n| rex field=timestring \"(?<label>\\S+)\"\n| eval v_type = typeof(timestring), l_type = typeof(label)\n| sort - label\n| fields label l_type timestring v_type"
            },
            "type": "ds.chain"
        },
        "ds_sfp5IIKQ": {
            "name": "mvexpand timestring passed",
            "options": {
                "query": "| makeresults format=csv data=\"mvexpand_rex_tok\n$mvexpand_rex_tok$\"\n| eval type = typeof(mvexpand_rex_tok)",
                "queryParameters": {
                    "earliest": "-24h@h",
                    "latest": "now"
                }
            },
            "type": "ds.search"
        },
        "ds_z6WkSe6U": {
            "name": "time string passed by label",
            "options": {
                "query": "| makeresults format=csv data=\"label_replace_tok\n$label_replace_tok$\"\n| eval type = typeof(label_replace_tok)",
                "queryParameters": {
                    "earliest": "-24h@h",
                    "latest": "now"
                }
            },
            "type": "ds.search"
        }
    },
    "layout": {
        "globalInputs": [
            "input_2qavhtpJ",
            "input_qjIV5Ix1",
            "input_1kIxDHKk",
            "input_R3Q1RvBK"
        ],
        "layoutDefinitions": {
            "layout_1": {
                "options": {
                    "height": 960,
                    "width": 1440
                },
                "structure": [
                    {
                        "item": "viz_KJJE0cri",
                        "position": {
                            "h": 339,
                            "w": 273,
                            "x": 0,
                            "y": 0
                        },
                        "type": "block"
                    },
                    {
                        "item": "viz_amq7ntem",
                        "position": {
                            "h": 136,
                            "w": 273,
                            "x": 0,
                            "y": 339
                        },
                        "type": "block"
                    },
                    {
                        "item": "viz_UsOo59WW",
                        "position": {
                            "h": 339,
                            "w": 376,
                            "x": 273,
                            "y": 0
                        },
                        "type": "block"
                    },
                    {
                        "item": "viz_bMEWY9PX",
                        "position": {
                            "h": 136,
                            "w": 376,
                            "x": 273,
                            "y": 339
                        },
                        "type": "block"
                    },
                    {
                        "item": "viz_93ySZ5Cc",
                        "position": {
                            "h": 339,
                            "w": 403,
                            "x": 649,
                            "y": 0
                        },
                        "type": "block"
                    },
                    {
                        "item": "viz_dvN9WkEw",
                        "position": {
                            "h": 136,
                            "w": 403,
                            "x": 649,
                            "y": 339
                        },
                        "type": "block"
                    },
                    {
                        "item": "viz_SMBNQ4XA",
                        "position": {
                            "h": 339,
                            "w": 388,
                            "x": 1052,
                            "y": 0
                        },
                        "type": "block"
                    },
                    {
                        "item": "viz_HaKyhXKv",
                        "position": {
                            "h": 136,
                            "w": 388,
                            "x": 1052,
                            "y": 339
                        },
                        "type": "block"
                    }
                ],
                "type": "grid"
            }
        },
        "options": {},
        "tabs": {
            "items": [
                {
                    "label": "New tab",
                    "layoutId": "layout_1"
                }
            ]
        }
    }
}

 

Screenshot 2026-02-01 at 10.14.09 PM.png

As the screenshot shows, even with labels correctly extracted, when DS considers the field as type time, the input dropdown uses extracted date followed by letter "T" and 0 hour 0 minute 0 second.  Are these all intentional?

Labels (2)
0 Karma

tscroggins
SplunkTrust
SplunkTrust

Hi @yuanliu,

Did you come up with a satisfying answer?

From my brief experiments, Dashboard Studio appears to cast or convert the field value to a JavaScript Date object using the Date.parse() method. If the string is in a date-time format recognized by the browser's JavaScript engine*, a valid Date object is returned, and Dashboard Studio gives the label or value a type of "time"; otherwise,  the label or value may have a type of "number," "string," or "unknown" depending on additional tests. The behavior changes when the search coerces a variant field to a specific type with, e.g., the replace() or tostring() functions.

If I'm poking around in the right spot, the logic is:

IF Finite AND Number THEN // x.isFinite() && x.isNumber(x)
    "number"
ELSE IF Date THEN // !Number.isNan(Date.parse(x))
    "time"
ELSE IF String THEN // Number.isNaN(Date.parse(x)) && typeof x == "string"
    "string"
ELSE
    "unknown"
END IF

There is necessarily some conversion from Splunk field to JavaScript variable when Dashboard Studio parses search results in client-side JavaScript.

The logic contradicts the behavior change, though, as date-time values coerced to strings should pass the (inferred) !Number.isNan(Date.parse(x)) test and have a type of "time" and not "string."

* Different browsers support different date-time string formats, but the standard formats should be universal.

0 Karma

yuanliu
SplunkTrust
SplunkTrust

I ended up using workarounds for visual effects when needed.  Here is an explanation from the DS team on Slack: "Splunk does use the ISO-8601 normalization, and the T separator is part of the standard, so that transformation itself is expected. The date label is also behaving as expected but I can see why showing the full timestamp could raise confusion."  They ask whether label extraction is the main concern.

From my perspective, the problem is forced, implied, and implicit typecasting.  Because time is not a defined data type in SPL, assuming that a string of format nnnn-nn-nn to be a date, nnn-nn-nnTnn:nn:nn to be time (and also nnn-nn-nn nn:nn:nn), then internally transforming its representation is too arbitrary.  Even in the narrow scope of label extraction, my original string is 2026-01-31 19:44:25; the implicit casting interprets this as 2026-01-31T19:44:25+00:00, i.e., in UTC.  Meanwhile, field label rex extracted would have string value of 2026-01-31, yet the implicit casting interprets that as 2026-01-31T08:00:00+00:00, i.e., in Pacific time when server and browser are set to Pacific time.  This shows inconsistence.  Inconsistence can cause even deeper problems.

0 Karma

tscroggins
SplunkTrust
SplunkTrust

Thanks for the Slack link. Dashboard Studio has gotten better at time zone detection relative to SplunkWeb user preferences and browser locale, but it would be clearer if it worked the same way every time, i.e., it used a zone offset if provided or else used the SplunkWeb offset.

There are other ways to confuse Dashboard Studio, e.g.:

| makeresults
| fieldformat _time=strftime(_time, "%d-%b-%Y")

_time is detected as a "time" field, but Dashboard Studio displays "Invalid Date" because the underlying JavaScript object is not a Date object.

0 Karma
Got questions? Get answers!

Join the Splunk Community Slack to learn, troubleshoot, and make connections with fellow Splunk practitioners in real time!

Meet up IRL or virtually!

Join Splunk User Groups to connect and learn in-person by region or remotely by topic or industry.

Get Updates on the Splunk Community!

A Four-Part Event Series: Full Stack Observability For the AI Era

As AI reshapes applications, infrastructure, and the way teams operate, the traditional boundaries of ...

SOC4Kafka - New Kafka Connector Powered by OpenTelemetry

The new SOC4Kafka connector, built on OpenTelemetry, enables the collection of Kafka messages and forwards ...

Event Series: Level up your SOC: Advancing with Splunk Enterprise Security

AI has fundamentally raised the stakes for security operations, and this three-part series is your guide to ...