I’m sure at one point every Python developer has been confused between the datetime module, and the datetime class inside that module.
Why does datetime.now() not work? Oh, it’s because this file does import datetime, instead of from datetime import datetime. In my experience, this is a common point of frustration.
This is also probably due to the fact that most people don’t realise that the datetime.datetime object is actually a class!
All these tiny problems will get sorted out, if class datetime was made class DateTime instead. There will be no ambiguity, and the class will now abide by the very common PascalCase convention as well.
I think this is worth changing, just for the reduction in ambiguity and accidental typos alone.
Plan of action: Definitely, if this were to be done, it would require a deprecation cycle. Most probably, 5 years or more.
And for the sake of uniformity, I’d also like to pursue the changing of date, time and timedelta in a similar fashion. (The lowercase time has problems of colliding with the time module anyway.)
Renaming would cause so much churn on its own that we’d be better off making a complete break or new module with a better API. DateTime shouldn’t be a subclass of Date since they have different assumptions (DateTime is a composition, not a subclass). Naive vs aware should work with typing.
1, You can’t just rename it; you have to first create an alias under the new name and deprecate the old name, only removing it after several versions.
2. You now have the problem that datetime.datetime, datetme.DateTime, and datetime, all are meaningful and all have subtle differences. The difference between datetime.datetime and datetime.DateTime will be the subtlest of all, in that code using the former will work on all versions up to X.Y but the latter will work on all versions from X.Z upward.
3. Since the class will want to be the same class, but can only have one name, you have to choose immediately whether to make pickles fail on all older versions, or make them fail in the future. You can’t have overlapping names in pickle.
4. And most importantly, a huge amount of churn across the entire ecosystem. Packages will have to update for no reason other than to avoid using the deprecated name. Documentation, tutorials, and code snippets will all become outdated. People’s muscle memories will be broken.
For this amount of upheaval, the benefit has to be very very real. Can you show that there is less disruption from the change than from keeping it the way it is?
Also - what do you propose to do about the very similar problem of pprint.pprint(), which isn’t a class?
Yeah, it seems to be a peculiarity of the scientific world, which I suspect means it has heritage from some other language. But there’s no reason not to encourage it, especially with something that risks ambiguity.
+1 on encouraging import datetime as dt (but hopefully WITHOUT ever encouraging from datetime import datetime as dt which would undo all the good work).
Looking through the rest of the stdlib, there aren’t actually all that many where I’d want a short alias, partly because any short alias would likely want to have other meaning (for example, shortening socket might be done as sock but that’s not much shorter, and anything less is going to be confusing - I don’t want to have import socket as so alongside import os when I start fat-fingering things!). Maybe import statistics as st? I don’t use the module enough to have a strong opinion.
The other big culprit in the “did you import the module or the thing from the module?” category is pprint. It’s probably going to cause some sniggering around the place, but other than that, import pprint as pp might be a good idea. Does anyone know if the converse (from pprint import pprint as pp) is done anywhere?
There’s initial support here, so you could create a pull request. We can sometimes skip issues for docs changes, but you can also open an issue first if you want more visibility.
I’d suggest updating the example code snippets, but a there’s lots with variables called dt so those would need renaming to avoid ambiguity. I’d suggest separate commits to ease review.
Personally, the possible ambiguity between module and class name and the length needed to call useful classmethods made me always use this style:
from datetime import date, datetime, timezone
from pprint import pformat, pprint
dt = datetime.now(timezone.utc)
pprint(all_the_things)
Contrary to os or sys, these function/class names are very clear to be used on their own, without module name, and I can always rely on the fact that when I read datetime it’s the class.
I don’t believe that docs using import datetime show a bug to be fixed, however.
Yes, maybe if we had a time machine and were redoing Python3 from scratch this would make sense. At this point, there’s just too much existing code and examples on the Internet to justify the churn and work this would cause.
I support the alias->lint warning->deprecation->removal over a decade or so.
Systems that are great are great because of a million tiny details.
Systems that are horrible are horrible because of a million tiny details.
Fixing many tiny details over time makes a much bigger improvement over time than normally understood when looking at one thing at a time. It’s similar to “everyone overestimates the work they can do in a year, and underestimates what they can do in a decade”. Small things are important too.
This is also true when the “million tiny details” are of the form of “Oh but if you’re on an older version of Python, use datetime instead of DateTime”. It’s one of the reasons I hate React.js with a passion - not because it is fundamentally bad software, but because there’s myriad breaking changes that mean examples and code snippets just stop working.
One problem with this is that you can’t rely on the lint warning. Suppose that, in Python 3.13, a new alias DateTime is added, with a promise that the original name will remain for at least ten years. You are responding to a person on this very Discourse about how to use this library. Do you say datetime or DateTime? The smart thing to do is to use the syntax that will work regardless of version, not the one that requires the user to have moved onto the latest and greatest version of Python. A few years later, someone finds your post. It’s still valid! Great. As you can see, it was correct for several years to completely ignore the new alias.
So that eats into the ten years quite badly. There is no incentive to use DateTime until it’s roughly as likely to work as datetime is. How quickly do people upgrade their Python versions? In what year will it be, say, 95% likely that your audience is on Python 3.13 or newer? It’s impossible to find general answers for those questions, of course, so let me ask it another way.
If someone comes to you saying “I use Python X.Y, please help with my problem”, how old must X.Y be before you’ll say “just upgrade to a newer Python”? Until that point, the DateTime alias is not useful. Your true deprecation period begins then.
I think a lot of the hesitancy towards change forwards that is displayed in this forum is the result of the emotional trauma of the 2 to 3 transition. There it took forever to phase out the old style. This isn’t the current situation though. Nowadays old versions are phased out quite rapidly.