{"record":{"id":"27254cec19d7443f","repo":"pandas-dev/pandas","slug":"cannot-directly-set-timezone-use-tz-localize-or","errorCode":null,"errorMessage":"Cannot directly set timezone. Use tz_localize() or tz_convert() as appropriate","messagePattern":"Cannot directly set timezone\\. Use tz_localize\\(\\) or tz_convert\\(\\) as appropriate","errorType":"exception","errorClass":"AttributeError","httpStatus":null,"severity":"error","filePath":"pandas/core/arrays/datetimes.py","lineNumber":651,"sourceCode":"        dtype: datetime64[us, UTC]\n        >>> s.dt.tz\n        datetime.timezone.utc\n\n        For DatetimeIndex:\n\n        >>> idx = pd.DatetimeIndex(\n        ...     [\"1/1/2020 10:00:00+00:00\", \"2/1/2020 11:00:00+00:00\"]\n        ... )\n        >>> idx.tz\n        datetime.timezone.utc\n        \"\"\"  # noqa: E501\n        # GH 18595\n        return getattr(self.dtype, \"tz\", None)\n\n    @tz.setter\n    def tz(self, value):\n        # GH 3746: Prevent localizing or converting the index by setting tz\n        raise AttributeError(\n            \"Cannot directly set timezone. Use tz_localize() \"\n            \"or tz_convert() as appropriate\"\n        )\n\n    @property\n    def tzinfo(self) -> tzinfo | None:\n        \"\"\"\n        Alias for tz attribute\n        \"\"\"\n        return self.tz\n\n    @property  # NB: override with cache_readonly in immutable subclasses\n    def is_normalized(self) -> bool:\n        \"\"\"\n        Returns True if all of the dates are at midnight (\"no time\")\n        \"\"\"\n        return is_date_array_normalized(self.asi8, self.tz, reso=self._creso)\n","sourceCodeStart":633,"sourceCodeEnd":669,"githubUrl":"https://github.com/pandas-dev/pandas/blob/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/core/arrays/datetimes.py#L633-L669","documentation":"Raised by the tz property setter of DatetimeArray/DatetimeIndex. The tz attribute is read-only because timezone changes are not in-place conversions — localizing (adding a tz) and converting (shifting across zones) are different operations with different semantics (and DST ambiguity handling), so they each get their own method.","triggerScenarios":"idx.tz = 'UTC' on a DatetimeIndex or DatetimeArray-backed Series.dt; series.index.tz = pytz.UTC; df.index.tz = None.","commonSituations":"Users from other libraries (or older pandas idioms) assuming index.tz is assignable. Quick interactive attempts to 'just add a zone'. Tutorial code copied from a non-pandas source.","solutions":["To attach a tz to naive data: idx = idx.tz_localize('UTC').","To switch zones on tz-aware data: idx = idx.tz_convert('US/Eastern').","To strip a tz: idx = idx.tz_localize(None)."],"exampleFix":"# before\nidx.tz = 'UTC'\n\n# after (naive -> aware)\nidx = idx.tz_localize('UTC')\n# or aware -> different zone\nidx = idx.tz_convert('UTC')","handlingStrategy":"validation","validationCode":"# do not assign; route to the correct API\nif want_attach_tz: idx = idx.tz_localize(tz)\nelif want_change_tz: idx = idx.tz_convert(tz)\nelif want_drop_tz: idx = idx.tz_localize(None)","typeGuard":null,"tryCatchPattern":"try:\n    idx.tz = tz\nexcept AttributeError as e:\n    if 'Cannot directly set timezone' in str(e):\n        idx = idx.tz_localize(tz) if idx.tz is None else idx.tz_convert(tz)\n    else: raise","preventionTips":["Treat .tz as read-only.","Lint for 'index.tz =' / '.tz =' assignments."],"tags":["datetime","timezone","read-only","attribute-error"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}