Force aware time in python

Viewed 128

Is there any way to force all time objects in Python to be aware, perhaps generating an error if I try to generate a naïve object?

Is there a way to tell whether a time object is naïve?

Trusting code to be non-naïve is not working for me and I'm getting bitten.

2 Answers

To tell if a datetime object is aware check its tzinfo attribute, as per the datetime doc says:

A datetime object d is aware if both of the following hold:

d.tzinfo is not None

d.tzinfo.utcoffset(d) does not return None

Otherwise, d is naive.

A time object t is aware if both of the following hold:

t.tzinfo is not None

t.tzinfo.utcoffset(None) does not return None.

As to how to force all datetimes to not be naive, there is a problem. Sometimes one simply does not have the timezone info.

Why not override datetime.datetime.__new__ in a subclass?

Notice how the method datetime.datetime.__new__ checks the timezone argument before creating new instances by calling the module level function:

# cpython/Lib/datetime.py
def _check_tzinfo_arg(tz):
    if tz is not None and not isinstance(tz, tzinfo):
        raise TypeError("tzinfo argument must be None or of a tzinfo subclass")

So we can invoke a similar check before calling datetime.datetime.__new__ in our subclass

import datetime

class AwareDate(datetime.datetime):
    def __new__(cls, *args, **kwargs):
        if not isinstance(kwargs.get('tzinfo', None), datetime.tzinfo):
            raise ValueError('MUST BE TZ AWARE !')

        return datetime.datetime.__new__(cls, *args, **kwargs)

Some quick tests

normaldate = datetime.datetime(2020, 12, 20, tzinfo=datetime.timezone.utc)
awaredate = AwareDate(2020, 12, 20, tzinfo=datetime.timezone.utc)
assert awaredate == normaldate

normaldate = datetime.datetime(2020, 12, 20)
awaredate = AwareDate(2020, 12, 20) # ValueError: MUST BE TZ AWARE!
Related