How can I enforce aware datetime objects?


Considering the difference between aware and naive datetime objects and that by default without specifying the tzinfo argument all datetime objects are “naive”, we’re in a bit of a pickle if we want to require aware datetime objects only and if we can’t control all creations of datetime objects (because third-party packages return them).

The proper way would be to subclass stdlib’s datetime class but that doesn’t ensure that all datetime objects are aware.

We could try and monkey patch the stdlib and hijack the datetime.__new__() function but that’s a built-in:

>>> datetime.datetime.__new__
<built-in method __new__ of type object at 0x101ac3b88>

and we can't set attributes of built-in/extension type 'datetime.datetime'. More interesting conversation here.

I think the ideal solution would be a way to “configure” the datetime class such that the tzinfo’s default argument could be changed, e.g. from None to timezone.utc. Short of such a feature, what do folks here suggest to work with this pickle?

Thank you!

1 Like

This seems like an XY problem. Naïve datetime objects have their uses (in fact, there’s not a better way to represent system local times) and trying to globally make it impossible to construct them would almost certainly be a bad idea.

If you want your interface to require aware datetimes, you should probably add some enforcement mechanism into the relevant functions or constructors that must take aware datetimes.

Another option would be to create a subclass of datetime.datetime that does not allow None for tzinfo. If you use static typing, you can annotate your functions to require this subclass.

It’s probably worth noting that this is not a good thing to do unless people are actually intending to represent a datetime in UTC when they create their datetime.datetime objects. It’s kind of like saying, “Well we want all numbers to have units, so we will make the default units meters for all numbers.” If someone is using numbers to mean miles or seconds or kilometers or parsecs, you have just made the situation more confusing, not less.

I think that in the light of type annotations in Python we see that bad design of the datetime module is that it uses the same type for both timezone aware and naïve objects. They should be distinct types so that static type analysis can detect many possible mistakes in our programs.

I hope this will get fixed at some point.

(Together with deprecating and removing datetime.utcnow() and datetime.utcfromtimestamp())

Related information: