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

rusackas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 1d4c3a2adb5 fix(core): don't blank a datetime column when its format 
coerces every value to NaT (#42405)
1d4c3a2adb5 is described below

commit 1d4c3a2adb5f4115c890fbfcbc39c3a98ce27a5d
Author: Evan Rusackas <[email protected]>
AuthorDate: Tue Jul 28 15:18:53 2026 -0700

    fix(core): don't blank a datetime column when its format coerces every 
value to NaT (#42405)
    
    Co-authored-by: Claude Code <[email protected]>
---
 superset/utils/core.py              | 15 ++++++++++++++-
 tests/unit_tests/utils/test_core.py | 16 ++++++++++++++++
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/superset/utils/core.py b/superset/utils/core.py
index 5810beba34a..09129c64eed 100644
--- a/superset/utils/core.py
+++ b/superset/utils/core.py
@@ -2017,13 +2017,26 @@ def _process_datetime_column(
 
         # Parse with or without format (suppress warning if no format)
         if format_to_use:
-            df[col.col_label] = pd.to_datetime(
+            converted = pd.to_datetime(
                 df[col.col_label],
                 utc=False,
                 format=format_to_use,
                 errors="coerce",
                 exact=False,
             )
+            # A format that coerces every non-null value to NaT is a mismatch
+            # (e.g. an epoch-millis column that inherited a '%Y' string format
+            # when used as a chart's granularity). Assigning it would silently
+            # blank the whole column, so keep the original values instead.
+            if df[col.col_label].notna().any() and not converted.notna().any():
+                logger.warning(
+                    "Datetime format %s coerced every value of column %s to 
NaT; "
+                    "keeping the original values",
+                    format_to_use,
+                    col.col_label,
+                )
+            else:
+                df[col.col_label] = converted
         else:
             with warnings.catch_warnings():
                 warnings.filterwarnings("ignore", message=".*Could not infer 
format.*")
diff --git a/tests/unit_tests/utils/test_core.py 
b/tests/unit_tests/utils/test_core.py
index 9a33ee55ed4..7fe3eee7eff 100644
--- a/tests/unit_tests/utils/test_core.py
+++ b/tests/unit_tests/utils/test_core.py
@@ -273,6 +273,22 @@ def test_normalize_dttm_col() -> None:
     assert df["__time"].astype(str).tolist() == ["2017-07-01"]
 
 
+def test_normalize_dttm_col_mismatched_format_keeps_values() -> None:
+    """A datetime format that coerces every value to NaT is a mismatch (e.g. an
+    epoch-millis column that inherited a ``%Y`` string format when used as a
+    chart's granularity); applying it would silently blank the whole column, so
+    the original values are kept instead of being nulled. Regression for the
+    Samples pane showing N/A for such columns."""
+    df = pd.DataFrame({"year": [1136073600000, 473385600000]})  # epoch ms
+    before = df["year"].tolist()
+
+    normalize_dttm_col(df, (DateColumn(col_label="year", 
timestamp_format="%Y"),))
+
+    # not blanked to NaT/None
+    assert df["year"].notna().all()
+    assert df["year"].tolist() == before
+
+
 def test_normalize_dttm_col_epoch_seconds() -> None:
     """Test conversion of epoch seconds."""
     df = pd.DataFrame(

Reply via email to