## TL;DR
You compared a timezone-aware datetime with a naive one, and Python/pandas refuses because the comparison is meaningless without knowing the offset. Fix it by making both sides the same: localize the naive side with `tz_localize`, or drop timezones with `tz_localize(None)`. Pick one convention for the whole pipeline and stick to it.

```text
TypeError: can't compare offset-naive and offset-aware datetimes
```

## Use this when
- Comparing datetimes raises the offset-naive vs offset-aware TypeError
- Subtracting two datetimes fails for the same reason
- Filtering a tz-aware pandas column with a naive timestamp

## Not for
- `to_datetime` parse failures, separate skill
- SQL timestamp/timestamptz issues
- Converting between timezones when both sides are already aware

## Steps

1. Check which side is which:

```python
print(a.tzinfo, b.tzinfo)
```
Expected output: one prints None (naive), the other prints a tzinfo (aware).

2. If the naive value is actually UTC, localize it:

```python
from zoneinfo import ZoneInfo
a = a.replace(tzinfo=ZoneInfo('UTC'))
```
Expected output: `a` is now aware, comparison works.

3. In pandas, localize the naive column or scalar:

```python
df['ts'] = df['ts'].dt.tz_localize('UTC')
```
Expected output: the column becomes datetime64 with tz, filters against aware values work.

4. Or strip timezones from the aware side when tz info is noise:

```python
df['ts'] = df['ts'].dt.tz_localize(None)
```
Expected output: naive datetimes, comparable with other naive values. Only do this if you know the data is all one zone.

5. For "now" comparisons, use the aware version:

```python
from datetime import datetime, timezone
datetime.now(timezone.utc) > aware_value
```
Expected output: a valid comparison. `datetime.now()` without tz is naive and will raise.

## Variant phrasings

### pandas cannot compare tz-naive and tz-aware
Same fix via `.dt.tz_localize` / `.dt.tz_convert`. Note `tz_localize` adds a zone to naive data; `tz_convert` moves aware data between zones. Mixing them up is the next most common error.

### astimezone() cannot be applied to a naive datetime
You called a conversion meant for aware datetimes on a naive one. Localize first, then convert.

### daylight saving time ambiguous time error
`tz_localize` can raise on ambiguous DST transitions; pass `ambiguous='NaT'` or `'infer'` to handle it explicitly.

## Why it happens
A naive datetime is a wall-clock reading with no zone attached; an aware one is an absolute instant. Comparing them requires assuming a zone for the naive one, and Python refuses to guess. Pandas inherits the rule.

## Edge cases
- `pd.Timestamp.now()` is naive; `pd.Timestamp.now(tz='UTC')` is aware. Know which you have.
- Parquet round-trips can silently drop tz info; verify dtypes after read.
- `tz_localize` on already-aware data raises; guard with a tzinfo check or use `tz_convert`.
- Store timestamps in UTC everywhere and convert to local zones only at display time; this whole error class mostly disappears.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_F-xMgx6WVg5m80KC1GSIjA
