Renaming datetime.datetime to datetime.DateTime

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.)

Thoughts? Is this worth pursuing?

8 Likes

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.

8 Likes

Instead, you’d have a new set of problems.

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?

2 Likes

I follow the advice of @adamchainz:

For these reasons, I use this import idiom and recommend you do too:

import datetime as dt

Rather than any of:

import datetime
from datetime import datetime  # or time, timezone

Then in your code, dt.datetime, dt.time, and dt.timezone will be unambiguous.

8 Likes

Could we mention import datetime as dt in the docs?

8 Likes

Couldn’t we make it so you could do:

from datetime import now

and under-the-hood it would really be datetime.datetime.now … not sure if that helps but could be interesting.

2 Likes

+1 on datetime as dt convention, reasonably well and way easier solution to the problem.

I’m up for updating the documentation, mentioning this as a reasonable convention and updating code examples. How do I get an approval for it?


Exposing datetime.datetime.now at the top level also sounds like a good idea, which should be easy and have reasonable benefit.

1 Like

There are a LOT of names in the stalib that don’t follow modern PEP conventions of capital class names. INcluding builtins like str, and tuple, and …

Also, in PYthon the distinction between a class and a factory function is sometimes subtle, so there is NO consistent naming convention.

So we need to jsut give up :slight_smile: – practicality beat purity.

I do like the import datetime as dt idiom – is there anywhere else in the stdlib where that’s recommended? It’s very common idiom in the scipy world:

import numpy as np
import panda as pd
import matplotlib.pyplot as plt
...

I also like adding a now() to the module namespace – I know why it’s a classmethod, but it always seemed awkward.

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?

Unlikely, because pprint.pp already exists.

So the convention (since 3.9) is to do from pprint import pp. So this one is a non issue now.

Oh, nice. Though not so nice in that import pprint as pp just introduces its own new ambiguity. Oh well.

I’d still support import datetime as dt though.

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.

Docs are here: datetime — Basic date and time types — Python 3.12.0a7 documentation

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.

1 Like

OK, turns out the import datetime is not done at all in the datetime module’s own documentation, there’s only from datetime import ... imports.

However, many other code examples in the docs do import datetime. A few in actual code as well.

Should I be updating those instead?

Change things like:

-from datetime import timedelta
-delta = timedelta(
+import datetime as dt
+delta = dt.timedelta(

And:

-from datetime import date
-date.fromisoformat('2019-12-04')
+import datetime as dt
+dt.date.fromisoformat('2019-12-04')

And:

-import datetime import datetime
-datetime.fromisoformat('2011-11-04')
+import datetime as dt
+dt.datetime.fromisoformat('2011-11-04')

And so on.

3 Likes

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.

5 Likes

No, I’ve never been confused.

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.

6 Likes

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.

2 Likes

100% agreed. But also, we can’t give up!

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.

4 Likes

I’m with you. Someone should make a list of all the names that don’t match PEP8.

3 Likes