There are several Python packages that implement the datetime.tzinfo interface, including pytz and dateutil. If someone hands me a timezone object and wants me to apply it to a datetime, the procedure is different depending on what kind of timezone object it is:
def apply_tz_to_datetime(dt: datetime.datetime, tz: datetime.tzinfo, ambiguous, nonexistent):
if isinstance(tz, dateutil.tz._common._tzinfo):
# do dt.replace(tz, fold=...)
elif isinstance(tz, pytz.tzinfo.BaseTzInfo):
# do tz.localize(dt, is_dst=...)
# other cases here
(The dateutil.tz case is a lot more complicated than I've shown, because there are a lot of cases to consider for non-existent or ambiguous datetimes, but the gist is always to either call dt.replace(tz, fold=...) or raise an exception.)
Checking dateutil.tz._common._tzinfo seems like a no-no, though, is there a better way?
I apologize for having to be the guy to say, "You shouldn't be doing that in the first place", but you indeed should not be trying to detect whether a time zone is a dateutil zone, you should instead just use it as a tzinfo object.
From your comments, it seems like the only reason you want to detect this is because pytz has a separate localization / normalization stage, but since pytz is the only library with this unusual interface, it should suffice to detect pytz zones.
As I mentioned in my comment on the dateutil issue, my recommendations are to either:
Not support pytz at all, if that is possible. It is effectively legacy software at this point, and if you have a new library you at least don't have any users who are already expecting to use it with pytz.
If that is not feasible, something like pytz-deprecation-shim might be a useful abstraction here. For a new library, I wouldn't recommend introducing time zones like those provided that also expose a pytz-like interface, but the helper functions (which don't require a dependency on pytz!) can be profitably used or re-implemented to either detect pytz zones or seamlessly upgrade them to their modern equivalents. You could also use this in combination with #1 by detecting if a zone is a pytz zone and throwing an error.
In any case, there is no particular reason to enumerate all the different time zone providers, since all except pytz use the standard interface.
It appears from the ratio of comments to answers (currently 9/0 = ∞), there is no available answer to the surface-level question (how to determine whether something is a dateutil.tz-style timezone object). I'll open a feature request ticket with the maintainers of the library.
Related
In Jinja2, how would you specify a default rendering method for a certain type?
In particular, datetime?
I found it quite annoying when rendering datetime values from Django. They look like 2022-11-04T00:00:00.987654+00:00. What was that T for, and why there was a plus + followed by 00:00. My users who lived on small islands for their entire life wouldn't understand.
Aside from the formatting problem, Django gives UTC time objects. Always UTC, despite the TIME_ZONE in its settings module has been specified with a different value.
I know I can use a filter thing like me.time_of_death|format_datetime. However putting it after every single datetime field sounds insane to me, and I don't want to be woken up in the midnight because of a datetime without that filter released on the previous day.
Is it possible to make it default?
You can use dateparse:
from django.utils import dateparse
Then when before you pass the time to the template you can use the following to convert it to something more understandable to your fellow islanders:
readable_time = dateparse.parse_datetime(CONFUSING_TIME_STRING)
The most recent zoneinfo database, as maintained by the Internet Assigned Numbers Authority, holds two new prefixes, 'posix' and 'right'. For example where there used to be just Asia/Kolkata the new database has added posix/Asia/Kolkata and right/Asia/Kolkata.
This database is also known as the Olson database after its first developer, or the tz database.
What do these newly added prefixes mean, and what's their practical effect? Can any of them safely be filtered out of timezone-choice picklists presented to users?
Globalized web apps (such as WordPress) use these zoneinfo names for user-preference picklists. They're in MySQL's timezone support setup.
right (or also leap, also zoneinfo-leaps) is about using times including leap seconds. Posix (also zoneinfo-posix, often just `zoneinfo) is about using POSIX times, so without considering leap seconds.
In theory you should not choose, the system choose it for you, considering how the time is stored in the system.
But no, for user you should not use data in zoneinfo.
To quote Python documentation:
Note
These values are not designed to be exposed to end-users; for user facing elements, applications should use something like CLDR (the Unicode Common Locale Data Repository) to get more user-friendly strings. See also the cautionary note on ZoneInfo.key.
Note: some zones are obsolete, and the text is simple ASCII, so it cannot represent correctly the city names, and the Englished version is not always the best one.
The right/ prefix marks timezones taking leap seconds into account.
The posix/ prefix marks timezones using, well, POSIX time. Those timezones are, practically, the same as the unprefixed ones.
It's probably fine to filter out the prefixed names when presenting timezone choices to users (the way WordPress, for example, does). If you're an astronomer your parsecage may vary.
I am a beginner in Python and trying to understand about working with dates and times. Could you help me understanding the following concept?
In time module, we have the ability to get the local time zone by doing the following,
import time
if time.daylight:
local_timezone_name = time.tzname[0]
utc_offset = time.timezone
else:
local_timezone_name = time.tzname[1]
utc_offset = time.altzone
So what I want to clarify are,
Isn't it suffice to just use the time module as above when dealing with local time zones instead of using pytz module? If not why pytz module is necessary?
What advantages do one gain by using pytz module when dealing with dates and times in Python? (I don't understand how it differs from what Python already has built into it and how it handles dates and times efficently?)
Thank you.
A long story.
Note: pytz is now obsolete (since two weeks), so with Python 3.9 you can uses directly standard libraries.
The problem: pytz is updated independently from Python releases, so it could change quickly the timezone changes. It is not so seldom that within a week or so a country decide to change daylight time implementation. This would cause a lot of problem using standard Python, were you do not update so often (and it will requires a lot of burdens, just to update one line in timezone file). So Python didn't include timezone information, but for UTC (but it could handle time offsets and daylight flag), and some information about your local timezone (and ev. daylight).
Now it seems they found a solution, but Python 3.9 is very new (it was released two weeks ago).
So, if you do not have python 3.9, pytz is the way to go. You have updated timezones and daylight periods.
The documentation for the datetime.timezone class only says:
A class that implements the tzinfo abstract base class as a fixed
offset from the UTC.
And it accepts a timedelta as its argument.
I never saw an example using it directly from other's code snippets, although I believe there must be some use of it, otherwise there is no point Python would expose this API. So in what situation would directly using this class be advised? What advantage would that be over using a dedicated library, such as pytz?
Update for python 3.6+ from the datetime docs is to no longer use pytz:
dateutil.tz library brings the IANA timezone database (also known as
the Olson database) to Python and its usage is recommended.
dateutil.tz is recommended over pytz because pytz handles datetime.timedelta operations in unexpected ways if the timezone has multiple offsets due to daylight savings time or some other reason. This article explains in more detail.
From the Python 3 documentation:
The datetime module supplies a simple concrete subclass of tzinfo,
timezone, which can represent timezones with fixed offset from UTC
such as UTC itself or North American EST and EDT.
The basic idea being that for timezones that are simply offsets of UTC time (i.e., UTC +/- some fixed number of minutes), implementing all the methods required for tzinfo objects is more effort than necessary, so you can simply subclass the timezone object with the offset value.
The documentation itself also recommends pytz for working with timezones:
pytz library brings the IANA timezone database (also known as the
Olson database) to Python and its usage is recommended
I've read a bunch of posts on how flaky parsing time can be. I believe I have come up with a reliable way of converting an ISO8601-formatted timestamp here:
https://gist.github.com/3702066
The most important part being the astimezone(LOCALZONE) call when the date is parsed. This allowed time.mktime() to do the right thing and appears to handle daylight savings properly.
Are there obvious gotchas I've missed?
Your code does seem to work even for times that fall just before or just after daylight savings time transitions, but I am afraid it might still fail on those rare occasions when a location's timezone offset actually changes. I don't have an example to test with though.
So even if if does work (or almost always work), I think it's crazy to convert a UTC time string to a UTC timestamp in a manner which involves or passed through local time in any way. The local time zone should be irrelevant. It's an unwanted dependency. I'm not saying that you're crazy. You're just trying to work with the APIs you are given, and the C library's time APIs are badly designed.
Luckily, Python provides an alternative to mktime() that is what the C library should have provided: calendar.timegm(). With this function, I can rewrite your function like this:
parsed = parse_date(timestamp)
timetuple = parsed.timetuple()
return calendar.timegm(timetuple)
Because local time is not involved, this also removes the dependency on pytz and the nagging doubt that an obscure artifact of somebody's local timezone will cause an unwanted effect.