4 ms·
I'm still annoyed that they are deprecating datetime.datetime.utcnow(). I have over 1000 references to that function in my projects folder. I understand the foo
by aftbit 3y ago
I'm still annoyed that they are deprecating datetime.datetime.utcnow(). I have over 1000 references to that function in my projects folder. I understand the footguns that naive datetimes present to the unwary, and yet I still prefer to work with naive always-UTC datetimes. Alas I will end up doing some kind of crazy find-and-replace (at least in the Python 3 code) to something like `datetime.datetime.now(tz=datetime.UTC).replace(tz=None)`. Then of course I'll have to track down all of the bugs from other people doing `from datetime import datetime` and refactor so I now import the whole module just to get a reference to UTC. Grr.
- dragonwriter 3y agoWouldn't it be easier just to write a utcnow() function of your own in a support module and do a find-and-replace to use that?
- amelius 3y agoAnother solution is to make a file called "my_patches.py": import datetime class my_datetime(datetime.datetime): @staticmethod def utcnow(): return datetime.datetime.now(tz=datetime.timezone.utc).replace(tzinfo=None) datetime.datetime = my_datetime And then in your codebase make sure you import my_patches whenever you use datetime. E.g.: import my_patches import datetime print(datetime.datetime.utcnow())
- kstrauser 3y agoThat solves the specific problem, but if you were my coworker, I’d have to toss you off the nearest bridge. Don’t monkeypatch Python, m’kay?
- js2 3y agoI think it's fine and pythonic[1,2] to monkey patch when used in moderation and done explicitly: from my_patches import monkey monkey.patch_datetime_utcnow() I wouldn't do it as a side-effect of an import. Down that path lies Ruby. :-) [1]: https://www.gevent.org/api/gevent.monkey.html https://www.gevent.org/api/gevent.monkey.html [2]: https://docs.pytest.org/en/6.2.x/monkeypatch.html https://docs.pytest.org/en/6.2.x/monkeypatch.html
- kstrauser 3y agoI disagree in general. A big part of gevent's raison d'etre was patching the stdlib to be async, so if a user read its docs at all, they’d be warned that it was making deep changes to the runtime. It's also very widely used and tested, so its changes are well exercised. Pytest helps you monkey patch code that can't easily be mocked in a different way, but it also helps you un-patch the code after your tests have finished. (Side note: if you find yourself patching a whole lot of things with pytest, it's probably time to look into techniques like dependency injection that can help free you from the need to patch in the first place.) But if you're not writing gevent or pytest, you should probably avoid it. It's much better to explicitly import or create the modified version of the code inside your own namespace, like: from helpers import my_datetime_utcnow or import datetime as dt def my_datetime_utcnow(): return dt.datetime.whatever... If you're going out of your way to patch the `datetime` namespace in such a way that other modules importing it get your patched version, it's quite likely that all hell will break loose when you least expect it.
- deleted 3y ago[deleted]
- Karellen 3y ago> I still prefer to work with naive always-UTC datetimes. Why prefer to work with naive UTC datetimes, rather than explicit UTC datetimes? What's wrong with plain `datetime.datetime.now(datetime.UTC)`?
- gmassman 3y agoI’m also curious to know why OP prefers naive to tz aware datetimes. IMO naive datetimes are a bad default, and `utcnow()` deserves to be deprecated.
- whalesalad 3y agoBecause many engineers decided long ago that you’d handle these concerns at the perimeter and assume UTC everywhere internally. Should and can be a decision left to the developer, no reason to take this away.
- aftbit 3y agoDatetimes are naive in my database. The fundamental problem with the change you recommend is that I cannot then compare those two different datetimes. For example, today I might do: user_over_30d_old = user.created_at < datetime.datetime.utcnow() - datetime.timedelta(30) But in the future, I would need to do: user_over_30d_old = user.created_at.replace(tzinfo=datetime.UTC) < datetime.datetime.now(datetime.UTC) - datetime.timedelta(30) Which isn't any better than the solution I proposed above, of removing UTC from the now() datetime. Alternatively, I could modify my DAL code to promote datetimes from naive to timezoned in the database at the edge of the python layer, but that would have a lot of knock-on effects in things like isoformat() now appending timezone information, which has caused issues in other broken APIs that I use.
- xorcist 3y agoAnd for no particularly good reason! Sure, it's not great, but lots of things aren't. It's at worst a possible footgun, otherwise mostly cosmetic. It should never be acceptable to break working software for anything else than critical security problems.
- fbdab103 3y agoNot sure I would go that far. APIs need to be able to be deprecated as better forms are identified. That being said, the churn had better be worth it. This datetime change does not qualify, and feels like it is going to cause more immediate pain than it solves.
- Kwpolska 3y agoIt is absolutely fine to deprecate badly designed APIs. It is fine if my 5-year-old program is full of deprecation warnings. It is not okay to delete APIs, breaking many programs, unless the APIs are well-known to be totally broken, infeasible to fix/maintain, and barely used.
- cozzyd 3y agoWelcome to Python
- aftbit 3y agoThis is one small benefit to working on a lot of Python 2.7 software. It never breaks anymore. Of course the deps are no longer updated and security issues are starting to pile up, but if your software doesn't process the wrong kinds of untrusted input, it will sure be more reliably run in python 2.7 in 5 years than if you wrote it in some flavor of python 3.
- whalesalad 3y agoI share your sentiment. I prefer naive datetimes that are always UTC. Fortunately I wrapped all of these methods in a core utility module ages ago so changing it won’t be very hard for our project… but still feels like a silly thing to deprecate for seemingly no reason.