Reputation: 13372
So, I have an aware datetime in ISO format - 2020-03-15T18:00:00+04:00
.
I want to parse it and validate that the tzinfo is "Asia/Dubai"
(UTC+04:00). Unfortunately, dateutil
& datetime
don't give me a good enough tzinfo
attribute on the parsed object, that I can easily verify.
>>> from datetime import datetime
>>> from dateutil.parser import isoparse
>>> import pytz
>>>
>>> dts = "2020-03-15T18:00:00+04:00"
>>> dt = datetime.fromisoformat(dts)
>>> dt.tzinfo
datetime.timezone(datetime.timedelta(seconds=14400))
>>> dt.tzinfo == pytz.timezone("Asia/Dubai")
False
>>>
>>> dt = isoparse(dts)
>>> dt.tzinfo
tzoffset(None, 14400)
>>> dt.tzinfo == pytz.timezone("Asia/Dubai")
False
I couldn't find how to deal with the tzoffset object so that I can compare it easily to the timezone string.
Any suggestions or comments or a nudge in the right direction are welcome.
Upvotes: 2
Views: 2719
Reputation: 10873
The answer to the question, "Is the parsed datetime 'Asia/Dubai'", particularly when your concept of 'Asia/Dubai' means pytz.timezone("Asia/Dubai")
is always "no", because dateutil
will never attach that time zone to something you have parsed from an ISO 8601 datetime.
One reason for this is that the string you are parsing does not have enough information to determine what set of rules generated it - consider that "Asia/Tibilisi" and "Asia/Dubai" both use UTC+4
, but they do not represent the same time zone.
So the question is: why do you need to know this information?
If you simply want to work with datetimes in "Asia/Dubai", the best thing to do is to convert them to it with .astimezone
:
from dateutil import tz
from dateutil.parser import isoparse
_DUBAI = tz.gettz("Asia/Dubai")
def parse_as_dubai(dt_str):
dt = isoparse(dt_str)
if dt.tzinfo is None:
raise ValueError(f"No time zone offset in {dt_str}")
return dt.astimezone(_DUBAI)
Note that as long as you have parsed a time zone, this will always be accurate, whether or not the input string was originally in "Asia/Dubai". If no time zone was given, using astimezone
will use the system local time of the system that is parsing the datetime, which is not what you want.
If for some reason you need to validate that the original datetime had the same offset as "Asia/Dubai" (not sure why you'd need this, but I suppose it could be indicative of a problem in the source of the datetimes), then converting to "Asia/Dubai" and checking that the offset is your best bet. You can add an additional error check in the code above:
from dateutil import tz
from dateutil.parser import isoparse
_DUBAI = tz.gettz("Asia/Dubai")
def parse_as_dubai(dt_str):
dt = isoparse(dt_str)
if dt.tzinfo is None:
raise ValueError(f"No time zone offset in {dt_str}")
rv = dt.astimezone(_DUBAI)
if dt.utcoffset() != rv.utcoffset():
raise ValueError(f"{dt_str} not generated in Asia/Dubai!")
return rv
As a final note, I would urge you not to use pytz
and instead to use dateutil.tz
, particularly since you are already using dateutil
for the parsing. You can read more about why in this article.
Upvotes: 2
Reputation: 13372
I found a workaround that I'm not a fan of (it should be little more trivial to compare timezones, but yes, it's a hard domain), based on this answer.
>>> tz = pytz.timezone("Asia/Dubai")
>>> datetime.utcoffset(dt) == tz.utcoffset(dt.replace(tzinfo=None))
True
Upvotes: 0