GothenburgBitFactory / tasklib

A Python library for interacting with taskwarrior databases.
http://tasklib.readthedocs.org/en/latest/
BSD 3-Clause "New" or "Revised" License
147 stars 28 forks source link

Using of proper TZ environment #106

Open mowgli opened 3 years ago

mowgli commented 3 years ago

Long time now, I have troubles with tools using tasklib due to a custom setting of TZ environment variable ("CET-1", without summertime)

While python is able to work correct with that

>>> import time
>>> time.tzname
('CET', 'CET')
>>> time.strftime('%X %x %Z')
'12:22:02 10/15/21 CET'

The Approach of tzlocal using ZoneInfo is completely broken and gives exceptions and wrong results. Some of the major troubles can be patched out of tzlocal by dropping the stupid asserts but the main problem remains that ZoneInfo is not able to parse proper TZ environment.

So please use the python base structures to use timezone instead of the broken tzlocal/ZoneInfo way.

tbabej commented 3 years ago

@mowgli Do you think you'd be able to pull together a PR that improves the timezone handling for the timezones of this format? :slightly_smiling_face:

mowgli commented 3 years ago

If it would have been perl, I would have answered that question with a clear yes. But I have no real clues of python. I could help with algorithmic ideas but not coding in python.

tbabej commented 3 years ago

Got it. Well, what would really help is if you could outline in more detail what were the parts of the codebase you needed to patch out in order to get your code working with the CET-1 timezone. I could then try to put a PR together, and have it reviewed by you in terms of whether it fixes the issue at hand.

mowgli commented 3 years ago

Well, in tzlocal is a assertion that went mad. So I just patched them out. It is not really a fix but it keep most of it from breaking and throwing stack traces:

Version 2.x:

--- a/tzlocal/unix.py
+++ b/tzlocal/unix.py
@@ -84,10 +84,6 @@ def _get_localzone(_root='/'):
                     if not etctz:
                         continue
                     tz = pytz.timezone(etctz.replace(' ', '_'))
-                    if _root == '/':
-                        # We are using a file in etc to name the timezone.
-                        # Verify that the timezone specified there is actually used:
-                        utils.assert_tz_offset(tz)
                     return tz

         except IOError:
@@ -122,10 +118,6 @@ def _get_localzone(_root='/'):

                     # We found a timezone
                     tz = pytz.timezone(etctz.replace(' ', '_'))
-                    if _root == '/':
-                        # We are using a file in etc to name the timezone.
-                        # Verify that the timezone specified there is actually used:
-                        utils.assert_tz_offset(tz)
                     return tz

         except IOError:

Version 3.x:

--- a/tzlocal/unix.py
+++ b/tzlocal/unix.py
@@ -90,10 +90,6 @@ def _get_localzone(_root='/'):
                     if not etctz:
                         continue
                     tz = ZoneInfo(etctz.replace(' ', '_'))
-                    if _root == '/':
-                        # We are using a file in etc to name the timezone.
-                        # Verify that the timezone specified there is actually used:
-                        utils.assert_tz_offset(tz)
                     return tz

         except (IOError, UnicodeDecodeError):
@@ -128,10 +124,6 @@ def _get_localzone(_root='/'):

                     # We found a timezone
                     tz = ZoneInfo(etctz.replace(' ', '_'))
-                    if _root == '/':
-                        # We are using a file in etc to name the timezone.
-                        # Verify that the timezone specified there is actually used:
-                        utils.assert_tz_offset(tz)
                     return tz

         except (IOError, UnicodeDecodeError) as e:

Version 1.5.1 was a last working version of tzlocal. Afterwards it gets more and more bad.

However, I do still not understand, why this is implemented that broken way and not using the python standard methods from time import which seems to do it the right way.

mowgli commented 3 years ago

Ah yes, even the 1.5.1 version was a bit wrong:

--- unix.py.orig        2020-03-05 15:31:48.600637137 +0100
+++ unix.py     2020-03-05 15:32:03.720637570 +0100
@@ -105,7 +105,7 @@
     if os.path.exists(tzpath) and os.path.islink(tzpath):
         tzpath = os.path.realpath(tzpath)
         start = tzpath.find("/")+1
-        while start is not 0:
+        while start != 0:
             tzpath = tzpath[start:]
             try:
                 return pytz.timezone(tzpath)
mowgli commented 3 years ago

There is another information, It seems that tzlocal changed its API between 2 and 3. And the later one is incompatible at all with tasklib.

tbabej commented 3 years ago

Is this true for the newest tasklib release? I was under the impression we are now compatible with tzlocal 3.x.

mowgli commented 3 years ago

I don't know. I use tasklib 2.3.4-r1 in gentoo. Devuan uses 2.4.3 but I have tzlocal on hold on that system with version 1.5.1 as this version had have only little trouble with python3 (see above).