You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by jl...@apache.org on 2026/09/16 00:33:36 UTC

(superset) 01/01: fix(time-format): stop reading short digit-only strings as epoch offsets

This is an automated email from the ASF dual-hosted git repository.

sadpandajoe pushed a commit to branch ultraset-fix-43847
in repository https://gitbox.apache.org/repos/asf/superset.git

commit f390d7e6f000a8c7262d9fe25d6f28f4c7581ee1
Author: sadpandajoe <sa...@users.noreply.github.com>
AuthorDate: Wed Sep 16 00:32:04 2026 +0000

    fix(time-format): stop reading short digit-only strings as epoch offsets
    
    stringifyTimeInput() only carved out the four-digit ISO year form
    (#43909); any other digit-only string, including a bare YYYYMMDD date
    key like "20260903", was still read as epoch milliseconds and rendered
    as 1970. Require at least 10 digits before treating a string as a
    plausible epoch timestamp; anything shorter that isn't a four-digit
    year now falls through to Date parsing and the existing NaN fallback,
    which returns the original value unchanged instead of a wrong date.
    
    Fixes #43847
    
    Co-Authored-By: Claude Sonnet 5 <no...@anthropic.com>
---
 .../src/time-format/utils/stringifyTimeInput.ts          | 15 ++++++++++-----
 .../test/time-format/utils/stringifyTimeInput.test.ts    | 16 ++++++++++++++++
 2 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/superset-frontend/packages/superset-ui-core/src/time-format/utils/stringifyTimeInput.ts b/superset-frontend/packages/superset-ui-core/src/time-format/utils/stringifyTimeInput.ts
index 1573d193ab6..6d336705b9e 100644
--- a/superset-frontend/packages/superset-ui-core/src/time-format/utils/stringifyTimeInput.ts
+++ b/superset-frontend/packages/superset-ui-core/src/time-format/utils/stringifyTimeInput.ts
@@ -29,15 +29,20 @@ export default function stringifyTimeInput(
   if (typeof value === 'string') {
     const trimmed = value.trim();
     // A bare four-digit string is the ISO 8601 year-only form ("2017"), which
-    // every engine parses as January 1st of that year. Any other integer
-    // string is an epoch timestamp in milliseconds that was stringified on
-    // its way here, e.g. by the pivot table, and is not a valid Date input.
+    // every engine parses as January 1st of that year. A digit-only string
+    // of at least 10 digits is long enough to plausibly be an epoch
+    // timestamp in milliseconds that was stringified on its way here, e.g.
+    // by the pivot table. Anything shorter that isn't a four-digit year -
+    // a YYYYMMDD date key such as "20260903", for instance - is neither, so
+    // it is handed to `new Date(value)` like any other string; that resolves
+    // to an Invalid Date and falls back to the original input below instead
+    // of being silently misread as a moment near 1970.
     const isYear = /^\d{4}$/.test(trimmed);
-    const isIntegerString = /^-?\d+$/.test(trimmed);
+    const isPlausibleEpoch = /^-?\d{10,}$/.test(trimmed);
     if (isYear) {
       time = new Date(trimmed);
     } else {
-      time = new Date(isIntegerString ? Number(trimmed) : value);
+      time = new Date(isPlausibleEpoch ? Number(trimmed) : value);
     }
   } else {
     time = value instanceof Date ? value : new Date(value);
diff --git a/superset-frontend/packages/superset-ui-core/test/time-format/utils/stringifyTimeInput.test.ts b/superset-frontend/packages/superset-ui-core/test/time-format/utils/stringifyTimeInput.test.ts
index 9fd9b8d68ce..73658596301 100644
--- a/superset-frontend/packages/superset-ui-core/test/time-format/utils/stringifyTimeInput.test.ts
+++ b/superset-frontend/packages/superset-ui-core/test/time-format/utils/stringifyTimeInput.test.ts
@@ -69,6 +69,22 @@ test('treats a four-digit integer string as a year, not as milliseconds', () =>
   );
 });
 
+test('does not treat a short non-year digit-only string as epoch milliseconds', () => {
+  // A YYYYMMDD date key or bare year-adjacent string like these is neither
+  // the four-digit year form nor long enough to plausibly be an epoch
+  // timestamp, so it must be left unchanged rather than silently rendered
+  // as a moment near 1970.
+  expect(stringifyTimeInput('20260903', format)).toBe('20260903');
+  expect(stringifyTimeInput('19870214', format)).toBe('19870214');
+  expect(stringifyTimeInput('999999999', format)).toBe('999999999');
+});
+
+test('treats a ten-digit integer string as epoch milliseconds', () => {
+  expect(stringifyTimeInput('1000000000', format)).toBe(
+    '1970-01-12T13:46:40.000Z',
+  );
+});
+
 test('returns the original input of an unparseable DateWithFormatter without re-entering the formatter', () => {
   // The `${value}` fallback calls `DateWithFormatter.toString()`, which must
   // return the input rather than call the formatter again, or the two would