{"record":{"id":"8fcc3d84bd356ebb","repo":"pandas-dev/pandas","slug":"cannot-add-subtract-timedelta-like-from-periodarra","errorCode":null,"errorMessage":"Cannot add/subtract timedelta-like from PeriodArray that is not an integer multiple of the PeriodArray's freq.","messagePattern":"Cannot add/subtract timedelta-like from PeriodArray that is not an integer multiple of the PeriodArray's freq\\.","errorType":"exception","errorClass":"IncompatibleFrequency","httpStatus":null,"severity":"error","filePath":"pandas/core/arrays/period.py","lineNumber":1283,"sourceCode":"        \"\"\"\n        if not self.dtype._is_tick_like():\n            # We cannot add timedelta-like to non-tick PeriodArray\n            raise TypeError(\n                f\"Cannot add or subtract timedelta64[ns] dtype from {self.dtype}\"\n            )\n\n        dtype = np.dtype(f\"m8[{self.dtype._td64_unit}]\")\n\n        # Similar to _check_timedeltalike_freq_compat, but we raise with a\n        #  more specific exception message if necessary.\n        try:\n            delta = astype_overflowsafe(\n                np.asarray(other), dtype=dtype, copy=False, round_ok=False\n            )\n        except ValueError as err:\n            # e.g. if we have minutes freq and try to add 30s\n            # \"Cannot losslessly convert units\"\n            raise IncompatibleFrequency(\n                \"Cannot add/subtract timedelta-like from PeriodArray that is \"\n                \"not an integer multiple of the PeriodArray's freq.\"\n            ) from err\n\n        res_values = add_overflowsafe(self.asi8, np.asarray(delta.view(\"i8\")))\n        return type(self)(res_values, dtype=self.dtype)\n\n    def _check_timedeltalike_freq_compat(self, other):\n        \"\"\"\n        Arithmetic operations with timedelta-like scalars or array `other`\n        are only valid if `other` is an integer multiple of `self.freq`.\n        If the operation is valid, find that integer multiple.  Otherwise,\n        raise because the operation is invalid.\n\n        Parameters\n        ----------\n        other : timedelta, np.timedelta64, Tick,\n                ndarray[timedelta64], TimedeltaArray, TimedeltaIndex","sourceCodeStart":1265,"sourceCodeEnd":1301,"githubUrl":"https://github.com/pandas-dev/pandas/blob/3b7651241d4da534b3559b60ef128e1c34f54116/pandas/core/arrays/period.py#L1265-L1301","documentation":"Raised by PeriodArray._time_shift when astype_overflowsafe cannot losslessly convert the timedelta operand into the period's timedelta unit (round_ok=False). The operation requires the delta to be an exact integer multiple of the period's tick; a sub-multiple (e.g. 30 seconds with a minute freq) cannot be represented and raises IncompatibleFrequency.","triggerScenarios":"minute_idx + pd.Timedelta('30s') — 30s is half a minute. daily_idx + np.timedelta64(12, 'h') — 12h is not a whole day. hourly_idx + pd.Timedelta('90s') where 90s doesn't divide the hour evenly into the array's unit.","commonSituations":"Sub-period deltas from sensor/IoT data; rounding errors in computed Timedeltas; mixing freq units (minutes + seconds) without alignment.","solutions":["Round the delta to a whole multiple of the period: (delta // idx.freq) * idx.freq, then add.","Switch to a finer period freq that the delta divides evenly (e.g. 's' instead of 'min').","Quantize the timedelta to the period unit before adding: delta.round(idx.freq)."],"exampleFix":"# before\nidx = pd.period_range('2023-01-01', periods=3, freq='min')\nidx + pd.Timedelta('30s')  # raises\n\n# after\nidx + pd.Timedelta('60s')   # whole-minute delta\n# or\nidx.to_timestamp() + pd.Timedelta('30s')","handlingStrategy":"validation","validationCode":"import pandas as pd\n\ndef add_timedelta_to_period(period_idx, delta):\n    freq = period_idx.freq\n    delta = pd.Timedelta(delta)\n    n_periods = delta // pd.Timedelta(freq.nanos) if hasattr(freq, 'nanos') else None\n    if n_periods is None or delta != n_periods * pd.Timedelta(freq.nanos):\n        raise ValueError(f'{delta} is not an integer multiple of {freq}')\n    return period_idx + int(n_periods) * freq","typeGuard":"import pandas as pd\n\ndef is_whole_period_multiple(delta, freq) -> bool:\n    try:\n        delta = pd.Timedelta(delta)\n        return delta == (delta // pd.Timedelta(freq.nanos)) * pd.Timedelta(freq.nanos)\n    except (ValueError, AttributeError, TypeError):\n        return False","tryCatchPattern":"try:\n    period_idx + delta\nexcept Exception as e:  # IncompatibleFrequency subclasses ValueError\n    if 'integer multiple' in str(e):\n        delta = (pd.Timedelta(delta) // pd.Timedelta(period_idx.freq.nanos)) * period_idx.freq\n        period_idx + delta\n    else:\n        raise","preventionTips":["Round sub-period timedeltas to whole multiples of idx.freq before adding.","Prefer integer period offsets (n * idx.freq) over raw Timedeltas for period arithmetic.","Drop to tick-like freq (e.g. 'min'->'s') when sub-period resolution is required."],"tags":["pandas","period","arithmetic","timedelta","freq","incompatible"],"backgroundTag":null,"analyzedSha":"3b7651241d4da534b3559b60ef128e1c34f54116","analyzedAt":"2026-08-11T22:10:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}