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")