pandas-dev/pandas · error · NotImplementedError

nonexistent is not supported.

Error message

nonexistent is not supported.

What it means

Raised by ArrowExtensionArray._round_temporally when `nonexistent != "raise"`. The pyarrow-backed dt.ceil/floor/round cannot resolve nonexistent (skipped) times that appear during DST spring-forward; only the default 'raise' is supported. Passing 'shift_forward', 'shift_backward', 'NaT', or a timedelta triggers NotImplementedError.

Source

Thrown at pandas/core/arrays/arrow/array.py:4174

    def _dt_normalize(self) -> Self:
        result = pc.floor_temporal(self._pa_array, 1, "day")
        return self._from_pyarrow_array(result)

    def _dt_strftime(self, format: str) -> Self:
        result = pc.strftime(self._pa_array, format=format)
        return self._from_pyarrow_array(result)

    def _round_temporally(
        self,
        method: Literal["ceil", "floor", "round"],
        freq,
        ambiguous: TimeAmbiguous = "raise",
        nonexistent: TimeNonexistent = "raise",
    ) -> Self:
        if ambiguous != "raise":
            raise NotImplementedError("ambiguous is not supported.")
        if nonexistent != "raise":
            raise NotImplementedError("nonexistent is not supported.")
        offset = to_offset(freq)
        if offset is None:
            raise ValueError(f"Must specify a valid frequency: {freq}")
        pa_supported_unit = {
            "Y": "year",
            "YS": "year",
            "Q": "quarter",
            "QS": "quarter",
            "M": "month",
            "MS": "month",
            "W": "week",
            "D": "day",
            "h": "hour",
            "min": "minute",
            "s": "second",
            "ms": "millisecond",
            "us": "microsecond",
            "ns": "nanosecond",

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Leave nonexistent at default 'raise' and filter/adjust the offending timestamps beforehand.
  2. Round in UTC then convert back: `s.dt.tz_convert("UTC").dt.floor("h").dt.tz_convert("US/Eastern")`.
  3. Cast to datetime64[ns, tz] for the operation: `s.astype("datetime64[ns, US/Eastern]").dt.floor("h", nonexistent="shift_forward")`.
  4. Drop DST timezone for rounding if precision loss is acceptable.

Example fix

# before
s.dt.floor("h", nonexistent="shift_forward")  # NotImplementedError

# after
out = s.dt.tz_convert("UTC").dt.floor("h").dt.tz_convert("US/Eastern")
Defensive patterns

Strategy: validation

Validate before calling

def safe_round(s, freq, method="floor", ambiguous="raise"):
    if getattr(s.dt, "tz", None) is not None:
        return s.dt.tz_convert("UTC").dt.__getattribute__(method)(freq, ambiguous=ambiguous).dt.tz_convert(s.dt.tz)
    return s.dt.__getattribute__(method)(freq, ambiguous=ambiguous)

Type guard

def needs_utc_rounding(s) -> bool:
    return getattr(s.dt, "tz", None) is not None

Try / catch

try:
    out = s.dt.ceil(freq, nonexistent=nonexistent)
except NotImplementedError:
    out = s.dt.tz_convert("UTC").dt.ceil(freq).dt.tz_convert(s.dt.tz)

Prevention

When it happens

Trigger: Calling `s.dt.ceil("h", nonexistent="shift_forward")` on a tz-aware pyarrow timestamp Series whose values fall in a DST gap (e.g. 02:00-03:00 on US spring-forward). Reached through dt.ceil/floor/round on timestamp[pyarrow, tz=...].

Common situations: Localizing/rounding logs or sensor data timestamped in a tz with DST; porting rounding code from numpy-backed datetime64 that accepted nonexistent kwargs.

Related errors


AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07). Data as JSON: /api/errors/b8c5d489c8ecb48a. Report an issue: GitHub.