clock: Detect system TZ (if possible) for cases where no TZ is specified

When the pytz dep was reintroduced, this made all TZ usage reliant upon
a tzinfo object generated by pytz. This had the effect of making the
``%Z`` strftime placeholder evaluate as blank when a timezone is not
explicitly defined (i.e. when the format is just a format string and
not a tuple containing the format string and timezone).

This commit resolves this regression by using pytz to build a tzinfo
object from either /etc/localtime or /etc/timezone during the ``init()``
function, establishing the system TZ to be used for those cases where no
TZ was specified.
This commit is contained in:
Erik Johnson 2016-08-31 22:17:05 -05:00
parent 03df1a644a
commit 3590dd20e5

View File

@ -1,7 +1,14 @@
import errno
import os import os
import locale import locale
from datetime import datetime from datetime import datetime
try:
import pytz
HAS_PYTZ = True
except ImportError:
HAS_PYTZ = False
from i3pystatus import IntervalModule from i3pystatus import IntervalModule
@ -85,21 +92,64 @@ class Clock(IntervalModule):
elif isinstance(self.format, str) or isinstance(self.format, tuple): elif isinstance(self.format, str) or isinstance(self.format, tuple):
self.format = [self.format] self.format = [self.format]
self.system_tz = self._get_system_tz()
self.format = [self._expand_format(fmt) for fmt in self.format] self.format = [self._expand_format(fmt) for fmt in self.format]
self.current_format_id = 0 self.current_format_id = 0
@staticmethod def _expand_format(self, fmt):
def _expand_format(fmt):
if isinstance(fmt, tuple): if isinstance(fmt, tuple):
if len(fmt) == 1: if len(fmt) == 1:
return (fmt[0], None) return (fmt[0], None)
else: else:
if not HAS_PYTZ:
raise RuntimeError("Need `pytz` for timezone data")
return (fmt[0], pytz.timezone(fmt[1]))
return (fmt, self.system_tz)
def _get_system_tz(self):
'''
Get the system timezone for use when no timezone is explicitly provided
Requires pytz, if not available then no timezone will be set when not
explicitly provided.
'''
if not HAS_PYTZ:
return None
def _etc_localtime():
try: try:
from pytz import timezone with open('/etc/localtime', 'rb') as fp:
except ImportError as e: return pytz.tzfile.build_tzinfo('system', fp)
raise RuntimeError("Need `pytz` for timezone data") from e except OSError as exc:
return (fmt[0], timezone(fmt[1])) if exc.errno != errno.ENOENT:
return (fmt, None) self.logger.error(
'Unable to read from /etc/localtime: %s', exc.strerror
)
except pytz.UnknownTimeZoneError:
self.logger.error(
'/etc/localtime contains unrecognized tzinfo'
)
return None
def _etc_timezone():
try:
with open('/etc/timezone', 'r') as fp:
tzname = fp.read().strip()
return pytz.timezone(tzname)
except OSError as exc:
if exc.errno != errno.ENOENT:
self.logger.error(
'Unable to read from /etc/localtime: %s', exc.strerror
)
except pytz.UnknownTimeZoneError:
self.logger.error(
'/etc/timezone contains unrecognized timezone \'%s\'',
tzname
)
return None
return _etc_localtime() or _etc_timezone()
def run(self): def run(self):
time = datetime.now(self.format[self.current_format_id][1]) time = datetime.now(self.format[self.current_format_id][1])