astral-sh / ruff

An extremely fast Python linter and code formatter, written in Rust.
https://docs.astral.sh/ruff
MIT License
31.52k stars 1.06k forks source link

DTZ007 - arguably a false positive #13359

Open rbubley opened 2 weeks ago

rbubley commented 2 weeks ago

A not uncommon pattern to parse a date string to a Python date uses similar code to the below. Times/time-zones shouldn't matter.

Ruff: DTZ007 Naive datetime constructed using `datetime.datetime.strptime()` without %z
  |
1 |         # Parse the date parameter
2 |         try:
3 |             input_date = datetime.strptime(date, "%Y-%m-%d").date()
  |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DTZ007
4 |         except ValueError:
5 |             print("Invalid date format. Use YYYY-MM-DD.")
  |
    = help: Call `.replace(tzinfo=<timezone>)` or `.astimezone()` to convert to an aware datetime
MichaReiser commented 2 weeks ago

To summarize your request: It is about detecting the specific usage of datetime.strptime where the pattern is %Y-%m-%d) which is followed by a call to date().

I'm not a datetime expert, but I think this pattern, indeed, doesn't require time zone information. The main challenge I see is that detecting this usage consistently without surprises requires quiet involved analysis. E.g what about:

input = datetime.strptime(date, "%Y-%m-%d")
input_date = input.date()

What if there are multiple statements in-between? That's why I think using a noqa comment in this situation is probably fine.

To me, using DateTime.strptime over date.fromisoformat would express the intent more clearly. What's your reason for preferring strptime?

rbubley commented 2 weeks ago

I think you are right. I had forgotten about date.fromisoformat.

(Although if the dates were in a different, non-ISO format, e.g. %d/%m/%Y, it's a bit more marginal).

MichaReiser commented 2 weeks ago

(Although if the dates were in a different, non-ISO format, e.g. %d/%m/%Y, it's a bit more marginal).

That's fair. I think adding a noqa in this situation is reasonable. We may be able to do better once we have type inference and can guarantee that the value returned by datetime.strptime isn't used anywhere else other than for calling .date.