Mercurial > repos > shellac > guppy_basecaller
diff env/lib/python3.7/site-packages/boltons/timeutils.py @ 5:9b1c78e6ba9c draft default tip
"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
author | shellac |
---|---|
date | Mon, 01 Jun 2020 08:59:25 -0400 |
parents | 79f47841a781 |
children |
line wrap: on
line diff
--- a/env/lib/python3.7/site-packages/boltons/timeutils.py Thu May 14 16:47:39 2020 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,548 +0,0 @@ -# -*- coding: utf-8 -*- -"""Python's :mod:`datetime` module provides some of the most complex -and powerful primitives in the Python standard library. Time is -nontrivial, but thankfully its support is first-class in -Python. ``dateutils`` provides some additional tools for working with -time. - -Additionally, timeutils provides a few basic utilities for working -with timezones in Python. The Python :mod:`datetime` module's -documentation describes how to create a -:class:`~datetime.datetime`-compatible :class:`~datetime.tzinfo` -subtype. It even provides a few examples. - -The following module defines usable forms of the timezones in those -docs, as well as a couple other useful ones, :data:`UTC` (aka GMT) and -:data:`LocalTZ` (representing the local timezone as configured in the -operating system). For timezones beyond these, as well as a higher -degree of accuracy in corner cases, check out `pytz`_ and `dateutil`_. - -.. _pytz: https://pypi.python.org/pypi/pytz -.. _dateutil: https://dateutil.readthedocs.io/en/stable/index.html -""" - -import re -import time -import bisect -import operator -from datetime import tzinfo, timedelta, date, datetime - - -def total_seconds(td): - """For those with older versions of Python, a pure-Python - implementation of Python 2.7's :meth:`~datetime.timedelta.total_seconds`. - - Args: - td (datetime.timedelta): The timedelta to convert to seconds. - Returns: - float: total number of seconds - - >>> td = timedelta(days=4, seconds=33) - >>> total_seconds(td) - 345633.0 - """ - a_milli = 1000000.0 - td_ds = td.seconds + (td.days * 86400) # 24 * 60 * 60 - td_micro = td.microseconds + (td_ds * a_milli) - return td_micro / a_milli - - -def dt_to_timestamp(dt): - """Converts from a :class:`~datetime.datetime` object to an integer - timestamp, suitable interoperation with :func:`time.time` and - other `Epoch-based timestamps`. - - .. _Epoch-based timestamps: https://en.wikipedia.org/wiki/Unix_time - - >>> abs(round(time.time() - dt_to_timestamp(datetime.utcnow()), 2)) - 0.0 - - ``dt_to_timestamp`` supports both timezone-aware and naïve - :class:`~datetime.datetime` objects. Note that it assumes naïve - datetime objects are implied UTC, such as those generated with - :meth:`datetime.datetime.utcnow`. If your datetime objects are - local time, such as those generated with - :meth:`datetime.datetime.now`, first convert it using the - :meth:`datetime.datetime.replace` method with ``tzinfo=`` - :class:`LocalTZ` object in this module, then pass the result of - that to ``dt_to_timestamp``. - """ - if dt.tzinfo: - td = dt - EPOCH_AWARE - else: - td = dt - EPOCH_NAIVE - return total_seconds(td) - - -_NONDIGIT_RE = re.compile(r'\D') - - -def isoparse(iso_str): - """Parses the limited subset of `ISO8601-formatted time`_ strings as - returned by :meth:`datetime.datetime.isoformat`. - - >>> epoch_dt = datetime.utcfromtimestamp(0) - >>> iso_str = epoch_dt.isoformat() - >>> print(iso_str) - 1970-01-01T00:00:00 - >>> isoparse(iso_str) - datetime.datetime(1970, 1, 1, 0, 0) - - >>> utcnow = datetime.utcnow() - >>> utcnow == isoparse(utcnow.isoformat()) - True - - For further datetime parsing, see the `iso8601`_ package for strict - ISO parsing and `dateutil`_ package for loose parsing and more. - - .. _ISO8601-formatted time: https://en.wikipedia.org/wiki/ISO_8601 - .. _iso8601: https://pypi.python.org/pypi/iso8601 - .. _dateutil: https://pypi.python.org/pypi/python-dateutil - - """ - dt_args = [int(p) for p in _NONDIGIT_RE.split(iso_str)] - return datetime(*dt_args) - - -_BOUNDS = [(0, timedelta(seconds=1), 'second'), - (1, timedelta(seconds=60), 'minute'), - (1, timedelta(seconds=3600), 'hour'), - (1, timedelta(days=1), 'day'), - (1, timedelta(days=7), 'week'), - (2, timedelta(days=30), 'month'), - (1, timedelta(days=365), 'year')] -_BOUNDS = [(b[0] * b[1], b[1], b[2]) for b in _BOUNDS] -_BOUND_DELTAS = [b[0] for b in _BOUNDS] - -_FLOAT_PATTERN = r'[+-]?\ *(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?' -_PARSE_TD_RE = re.compile(r"((?P<value>%s)\s*(?P<unit>\w)\w*)" % _FLOAT_PATTERN) -_PARSE_TD_KW_MAP = dict([(unit[0], unit + 's') - for _, _, unit in reversed(_BOUNDS[:-2])]) - - -def parse_timedelta(text): - """Robustly parses a short text description of a time period into a - :class:`datetime.timedelta`. Supports weeks, days, hours, minutes, - and seconds, with or without decimal points: - - Args: - text (str): Text to parse. - Returns: - datetime.timedelta - Raises: - ValueError: on parse failure. - - >>> parse_td('1d 2h 3.5m 0s') == timedelta(days=1, seconds=7410) - True - - Also supports full words and whitespace. - - >>> parse_td('2 weeks 1 day') == timedelta(days=15) - True - - Negative times are supported, too: - - >>> parse_td('-1.5 weeks 3m 20s') == timedelta(days=-11, seconds=43400) - True - """ - td_kwargs = {} - for match in _PARSE_TD_RE.finditer(text): - value, unit = match.group('value'), match.group('unit') - try: - unit_key = _PARSE_TD_KW_MAP[unit] - except KeyError: - raise ValueError('invalid time unit %r, expected one of %r' - % (unit, _PARSE_TD_KW_MAP.keys())) - try: - value = float(value) - except ValueError: - raise ValueError('invalid time value for unit %r: %r' - % (unit, value)) - td_kwargs[unit_key] = value - return timedelta(**td_kwargs) - - -parse_td = parse_timedelta # legacy alias - - -def _cardinalize_time_unit(unit, value): - # removes dependency on strutils; nice and simple because - # all time units cardinalize normally - if value == 1: - return unit - return unit + 's' - - -def decimal_relative_time(d, other=None, ndigits=0, cardinalize=True): - """Get a tuple representing the relative time difference between two - :class:`~datetime.datetime` objects or one - :class:`~datetime.datetime` and now. - - Args: - d (datetime): The first datetime object. - other (datetime): An optional second datetime object. If - unset, defaults to the current time as determined - :meth:`datetime.utcnow`. - ndigits (int): The number of decimal digits to round to, - defaults to ``0``. - cardinalize (bool): Whether to pluralize the time unit if - appropriate, defaults to ``True``. - Returns: - (float, str): A tuple of the :class:`float` difference and - respective unit of time, pluralized if appropriate and - *cardinalize* is set to ``True``. - - Unlike :func:`relative_time`, this method's return is amenable to - localization into other languages and custom phrasing and - formatting. - - >>> now = datetime.utcnow() - >>> decimal_relative_time(now - timedelta(days=1, seconds=3600), now) - (1.0, 'day') - >>> decimal_relative_time(now - timedelta(seconds=0.002), now, ndigits=5) - (0.002, 'seconds') - >>> decimal_relative_time(now, now - timedelta(days=900), ndigits=1) - (-2.5, 'years') - - """ - if other is None: - other = datetime.utcnow() - diff = other - d - diff_seconds = total_seconds(diff) - abs_diff = abs(diff) - b_idx = bisect.bisect(_BOUND_DELTAS, abs_diff) - 1 - bbound, bunit, bname = _BOUNDS[b_idx] - f_diff = diff_seconds / total_seconds(bunit) - rounded_diff = round(f_diff, ndigits) - if cardinalize: - return rounded_diff, _cardinalize_time_unit(bname, abs(rounded_diff)) - return rounded_diff, bname - - -def relative_time(d, other=None, ndigits=0): - """Get a string representation of the difference between two - :class:`~datetime.datetime` objects or one - :class:`~datetime.datetime` and the current time. Handles past and - future times. - - Args: - d (datetime): The first datetime object. - other (datetime): An optional second datetime object. If - unset, defaults to the current time as determined - :meth:`datetime.utcnow`. - ndigits (int): The number of decimal digits to round to, - defaults to ``0``. - Returns: - A short English-language string. - - >>> now = datetime.utcnow() - >>> relative_time(now, ndigits=1) - '0 seconds ago' - >>> relative_time(now - timedelta(days=1, seconds=36000), ndigits=1) - '1.4 days ago' - >>> relative_time(now + timedelta(days=7), now, ndigits=1) - '1 week from now' - - """ - drt, unit = decimal_relative_time(d, other, ndigits, cardinalize=True) - phrase = 'ago' - if drt < 0: - phrase = 'from now' - return '%g %s %s' % (abs(drt), unit, phrase) - - -def strpdate(string, format): - """Parse the date string according to the format in `format`. Returns a - :class:`date` object. Internally, :meth:`datetime.strptime` is used to - parse the string and thus conversion specifiers for time fields (e.g. `%H`) - may be provided; these will be parsed but ignored. - - Args: - string (str): The date string to be parsed. - format (str): The `strptime`_-style date format string. - Returns: - datetime.date - - .. _`strptime`: https://docs.python.org/2/library/datetime.html#strftime-strptime-behavior - - >>> strpdate('2016-02-14', '%Y-%m-%d') - datetime.date(2016, 2, 14) - >>> strpdate('26/12 (2015)', '%d/%m (%Y)') - datetime.date(2015, 12, 26) - >>> strpdate('20151231 23:59:59', '%Y%m%d %H:%M:%S') - datetime.date(2015, 12, 31) - >>> strpdate('20160101 00:00:00.001', '%Y%m%d %H:%M:%S.%f') - datetime.date(2016, 1, 1) - """ - whence = datetime.strptime(string, format) - return whence.date() - - -def daterange(start, stop, step=1, inclusive=False): - """In the spirit of :func:`range` and :func:`xrange`, the `daterange` - generator that yields a sequence of :class:`~datetime.date` - objects, starting at *start*, incrementing by *step*, until *stop* - is reached. - - When *inclusive* is True, the final date may be *stop*, **if** - *step* falls evenly on it. By default, *step* is one day. See - details below for many more details. - - Args: - start (datetime.date): The starting date The first value in - the sequence. - stop (datetime.date): The stopping date. By default not - included in return. Can be `None` to yield an infinite - sequence. - step (int): The value to increment *start* by to reach - *stop*. Can be an :class:`int` number of days, a - :class:`datetime.timedelta`, or a :class:`tuple` of integers, - `(year, month, day)`. Positive and negative *step* values - are supported. - inclusive (bool): Whether or not the *stop* date can be - returned. *stop* is only returned when a *step* falls evenly - on it. - - >>> christmas = date(year=2015, month=12, day=25) - >>> boxing_day = date(year=2015, month=12, day=26) - >>> new_year = date(year=2016, month=1, day=1) - >>> for day in daterange(christmas, new_year): - ... print(repr(day)) - datetime.date(2015, 12, 25) - datetime.date(2015, 12, 26) - datetime.date(2015, 12, 27) - datetime.date(2015, 12, 28) - datetime.date(2015, 12, 29) - datetime.date(2015, 12, 30) - datetime.date(2015, 12, 31) - >>> for day in daterange(christmas, boxing_day): - ... print(repr(day)) - datetime.date(2015, 12, 25) - >>> for day in daterange(date(2017, 5, 1), date(2017, 8, 1), - ... step=(0, 1, 0), inclusive=True): - ... print(repr(day)) - datetime.date(2017, 5, 1) - datetime.date(2017, 6, 1) - datetime.date(2017, 7, 1) - datetime.date(2017, 8, 1) - - *Be careful when using stop=None, as this will yield an infinite - sequence of dates.* - """ - if not isinstance(start, date): - raise TypeError("start expected datetime.date instance") - if stop and not isinstance(stop, date): - raise TypeError("stop expected datetime.date instance or None") - try: - y_step, m_step, d_step = step - except TypeError: - y_step, m_step, d_step = 0, 0, step - else: - y_step, m_step = int(y_step), int(m_step) - if isinstance(d_step, int): - d_step = timedelta(days=int(d_step)) - elif isinstance(d_step, timedelta): - pass - else: - raise ValueError('step expected int, timedelta, or tuple' - ' (year, month, day), not: %r' % step) - - if stop is None: - finished = lambda now, stop: False - elif start < stop: - finished = operator.gt if inclusive else operator.ge - else: - finished = operator.lt if inclusive else operator.le - now = start - - while not finished(now, stop): - yield now - if y_step or m_step: - m_y_step, cur_month = divmod(now.month + m_step, 12) - now = now.replace(year=now.year + y_step + m_y_step, - month=cur_month or 12) - now = now + d_step - return - - -# Timezone support (brought in from tzutils) - - -ZERO = timedelta(0) -HOUR = timedelta(hours=1) - - -class ConstantTZInfo(tzinfo): - """ - A :class:`~datetime.tzinfo` subtype whose *offset* remains constant - (no daylight savings). - - Args: - name (str): Name of the timezone. - offset (datetime.timedelta): Offset of the timezone. - """ - def __init__(self, name="ConstantTZ", offset=ZERO): - self.name = name - self.offset = offset - - @property - def utcoffset_hours(self): - return total_seconds(self.offset) / (60 * 60) - - def utcoffset(self, dt): - return self.offset - - def tzname(self, dt): - return self.name - - def dst(self, dt): - return ZERO - - def __repr__(self): - cn = self.__class__.__name__ - return '%s(name=%r, offset=%r)' % (cn, self.name, self.offset) - - -UTC = ConstantTZInfo('UTC') -EPOCH_AWARE = datetime.fromtimestamp(0, UTC) -EPOCH_NAIVE = datetime.utcfromtimestamp(0) - - -class LocalTZInfo(tzinfo): - """The ``LocalTZInfo`` type takes data available in the time module - about the local timezone and makes a practical - :class:`datetime.tzinfo` to represent the timezone settings of the - operating system. - - For a more in-depth integration with the operating system, check - out `tzlocal`_. It builds on `pytz`_ and implements heuristics for - many versions of major operating systems to provide the official - ``pytz`` tzinfo, instead of the LocalTZ generalization. - - .. _tzlocal: https://pypi.python.org/pypi/tzlocal - .. _pytz: https://pypi.python.org/pypi/pytz - - """ - _std_offset = timedelta(seconds=-time.timezone) - _dst_offset = _std_offset - if time.daylight: - _dst_offset = timedelta(seconds=-time.altzone) - - def is_dst(self, dt): - dt_t = (dt.year, dt.month, dt.day, dt.hour, dt.minute, - dt.second, dt.weekday(), 0, -1) - local_t = time.localtime(time.mktime(dt_t)) - return local_t.tm_isdst > 0 - - def utcoffset(self, dt): - if self.is_dst(dt): - return self._dst_offset - return self._std_offset - - def dst(self, dt): - if self.is_dst(dt): - return self._dst_offset - self._std_offset - return ZERO - - def tzname(self, dt): - return time.tzname[self.is_dst(dt)] - - def __repr__(self): - return '%s()' % self.__class__.__name__ - - -LocalTZ = LocalTZInfo() - - -def _first_sunday_on_or_after(dt): - days_to_go = 6 - dt.weekday() - if days_to_go: - dt += timedelta(days_to_go) - return dt - - -# US DST Rules -# -# This is a simplified (i.e., wrong for a few cases) set of rules for US -# DST start and end times. For a complete and up-to-date set of DST rules -# and timezone definitions, visit the Olson Database (or try pytz): -# http://www.twinsun.com/tz/tz-link.htm -# http://sourceforge.net/projects/pytz/ (might not be up-to-date) -# -# In the US, since 2007, DST starts at 2am (standard time) on the second -# Sunday in March, which is the first Sunday on or after Mar 8. -DSTSTART_2007 = datetime(1, 3, 8, 2) -# and ends at 2am (DST time; 1am standard time) on the first Sunday of Nov. -DSTEND_2007 = datetime(1, 11, 1, 1) -# From 1987 to 2006, DST used to start at 2am (standard time) on the first -# Sunday in April and to end at 2am (DST time; 1am standard time) on the last -# Sunday of October, which is the first Sunday on or after Oct 25. -DSTSTART_1987_2006 = datetime(1, 4, 1, 2) -DSTEND_1987_2006 = datetime(1, 10, 25, 1) -# From 1967 to 1986, DST used to start at 2am (standard time) on the last -# Sunday in April (the one on or after April 24) and to end at 2am (DST time; -# 1am standard time) on the last Sunday of October, which is the first Sunday -# on or after Oct 25. -DSTSTART_1967_1986 = datetime(1, 4, 24, 2) -DSTEND_1967_1986 = DSTEND_1987_2006 - - -class USTimeZone(tzinfo): - """Copied directly from the Python docs, the ``USTimeZone`` is a - :class:`datetime.tzinfo` subtype used to create the - :data:`Eastern`, :data:`Central`, :data:`Mountain`, and - :data:`Pacific` tzinfo types. - """ - def __init__(self, hours, reprname, stdname, dstname): - self.stdoffset = timedelta(hours=hours) - self.reprname = reprname - self.stdname = stdname - self.dstname = dstname - - def __repr__(self): - return self.reprname - - def tzname(self, dt): - if self.dst(dt): - return self.dstname - else: - return self.stdname - - def utcoffset(self, dt): - return self.stdoffset + self.dst(dt) - - def dst(self, dt): - if dt is None or dt.tzinfo is None: - # An exception may be sensible here, in one or both cases. - # It depends on how you want to treat them. The default - # fromutc() implementation (called by the default astimezone() - # implementation) passes a datetime with dt.tzinfo is self. - return ZERO - assert dt.tzinfo is self - - # Find start and end times for US DST. For years before 1967, return - # ZERO for no DST. - if 2006 < dt.year: - dststart, dstend = DSTSTART_2007, DSTEND_2007 - elif 1986 < dt.year < 2007: - dststart, dstend = DSTSTART_1987_2006, DSTEND_1987_2006 - elif 1966 < dt.year < 1987: - dststart, dstend = DSTSTART_1967_1986, DSTEND_1967_1986 - else: - return ZERO - - start = _first_sunday_on_or_after(dststart.replace(year=dt.year)) - end = _first_sunday_on_or_after(dstend.replace(year=dt.year)) - - # Can't compare naive to aware objects, so strip the timezone - # from dt first. - if start <= dt.replace(tzinfo=None) < end: - return HOUR - else: - return ZERO - - -Eastern = USTimeZone(-5, "Eastern", "EST", "EDT") -Central = USTimeZone(-6, "Central", "CST", "CDT") -Mountain = USTimeZone(-7, "Mountain", "MST", "MDT") -Pacific = USTimeZone(-8, "Pacific", "PST", "PDT")