mirror of https://github.com/mahmoud/boltons.git
merging tzutils into timeutils, lots of little timeutils docs enhancements
This commit is contained in:
parent
13d5ee88c7
commit
027865d9ce
|
@ -371,7 +371,7 @@ def iter_find_files(directory, patterns, ignored=None):
|
||||||
|
|
||||||
>>> filenames = sorted(iter_find_files(_CUR_DIR, '*.py'))
|
>>> filenames = sorted(iter_find_files(_CUR_DIR, '*.py'))
|
||||||
>>> filenames[-1].split('/')[-1]
|
>>> filenames[-1].split('/')[-1]
|
||||||
'tzutils.py'
|
'typeutils.py'
|
||||||
|
|
||||||
Or, Python files while ignoring emacs lockfiles:
|
Or, Python files while ignoring emacs lockfiles:
|
||||||
|
|
||||||
|
|
|
@ -5,18 +5,25 @@ nontrivial, but thankfully its support is first-class in
|
||||||
Python. ``dateutils`` provides some additional tools for working with
|
Python. ``dateutils`` provides some additional tools for working with
|
||||||
time.
|
time.
|
||||||
|
|
||||||
See :mod:`tzutils` for handy timezone-related boltons.
|
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`_.
|
||||||
|
|
||||||
|
.. _pytz: https://pypi.python.org/pypi/pytz
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
import time
|
||||||
import bisect
|
import bisect
|
||||||
import datetime
|
from datetime import tzinfo, timedelta, datetime
|
||||||
from datetime import timedelta
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['total_seconds', 'isoparse', 'parse_td', 'relative_time',
|
|
||||||
'decimal_relative_time']
|
|
||||||
|
|
||||||
|
|
||||||
def total_seconds(td):
|
def total_seconds(td):
|
||||||
|
@ -28,7 +35,7 @@ def total_seconds(td):
|
||||||
Returns:
|
Returns:
|
||||||
float: total number of seconds
|
float: total number of seconds
|
||||||
|
|
||||||
>>> td = datetime.timedelta(days=4, seconds=33)
|
>>> td = timedelta(days=4, seconds=33)
|
||||||
>>> total_seconds(td)
|
>>> total_seconds(td)
|
||||||
345633.0
|
345633.0
|
||||||
"""
|
"""
|
||||||
|
@ -42,28 +49,30 @@ _NONDIGIT_RE = re.compile('\D')
|
||||||
|
|
||||||
|
|
||||||
def isoparse(iso_str):
|
def isoparse(iso_str):
|
||||||
"""Parses the very limited subset of ISO8601 as returned by
|
"""Parses the limited subset of `ISO8601-formatted time`_ strings as
|
||||||
:meth:`datetime.datetime.isoformat`.
|
returned by :meth:`datetime.datetime.isoformat`.
|
||||||
|
|
||||||
>>> epoch_dt = datetime.datetime.utcfromtimestamp(0)
|
>>> epoch_dt = datetime.utcfromtimestamp(0)
|
||||||
>>> iso_str = epoch_dt.isoformat()
|
>>> iso_str = epoch_dt.isoformat()
|
||||||
>>> print(iso_str)
|
>>> print(iso_str)
|
||||||
1970-01-01T00:00:00
|
1970-01-01T00:00:00
|
||||||
>>> isoparse(iso_str)
|
>>> isoparse(iso_str)
|
||||||
datetime.datetime(1970, 1, 1, 0, 0)
|
datetime.datetime(1970, 1, 1, 0, 0)
|
||||||
|
|
||||||
>>> utcnow = datetime.datetime.utcnow()
|
>>> utcnow = datetime.utcnow()
|
||||||
>>> utcnow == isoparse(utcnow.isoformat())
|
>>> utcnow == isoparse(utcnow.isoformat())
|
||||||
True
|
True
|
||||||
|
|
||||||
For further datetime parsing, see the `iso8601`_ package for strict
|
For further datetime parsing, see the `iso8601`_ package for strict
|
||||||
ISO parsing and `dateutil`_ package for loose parsing and more.
|
ISO parsing and `dateutil`_ package for loose parsing and more.
|
||||||
|
|
||||||
|
.. _ISO8601-formatted time strings: https://en.wikipedia.org/wiki/ISO_8601
|
||||||
.. _iso8601: https://pypi.python.org/pypi/iso8601
|
.. _iso8601: https://pypi.python.org/pypi/iso8601
|
||||||
.. _dateutil: https://pypi.python.org/pypi/python-dateutil
|
.. _dateutil: https://pypi.python.org/pypi/python-dateutil
|
||||||
|
|
||||||
"""
|
"""
|
||||||
dt_args = [int(p) for p in _NONDIGIT_RE.split(iso_str)]
|
dt_args = [int(p) for p in _NONDIGIT_RE.split(iso_str)]
|
||||||
return datetime.datetime(*dt_args)
|
return datetime(*dt_args)
|
||||||
|
|
||||||
|
|
||||||
_BOUNDS = [(0, timedelta(seconds=1), 'second'),
|
_BOUNDS = [(0, timedelta(seconds=1), 'second'),
|
||||||
|
@ -157,7 +166,7 @@ def decimal_relative_time(d, other=None, ndigits=0, cardinalize=True):
|
||||||
localization into other languages and custom phrasing and
|
localization into other languages and custom phrasing and
|
||||||
formatting.
|
formatting.
|
||||||
|
|
||||||
>>> now = datetime.datetime.utcnow()
|
>>> now = datetime.utcnow()
|
||||||
>>> decimal_relative_time(now - timedelta(days=1, seconds=3600), now)
|
>>> decimal_relative_time(now - timedelta(days=1, seconds=3600), now)
|
||||||
(1.0, 'day')
|
(1.0, 'day')
|
||||||
>>> decimal_relative_time(now - timedelta(seconds=0.002), now, ndigits=5)
|
>>> decimal_relative_time(now - timedelta(seconds=0.002), now, ndigits=5)
|
||||||
|
@ -166,7 +175,7 @@ def decimal_relative_time(d, other=None, ndigits=0, cardinalize=True):
|
||||||
(-2.5, 'years')
|
(-2.5, 'years')
|
||||||
"""
|
"""
|
||||||
if other is None:
|
if other is None:
|
||||||
other = datetime.datetime.utcnow()
|
other = datetime.utcnow()
|
||||||
diff = other - d
|
diff = other - d
|
||||||
diff_seconds = total_seconds(diff)
|
diff_seconds = total_seconds(diff)
|
||||||
abs_diff = abs(diff)
|
abs_diff = abs(diff)
|
||||||
|
@ -194,7 +203,7 @@ def relative_time(d, other=None, ndigits=0):
|
||||||
Returns:
|
Returns:
|
||||||
A short English-language string.
|
A short English-language string.
|
||||||
|
|
||||||
>>> now = datetime.datetime.utcnow()
|
>>> now = datetime.utcnow()
|
||||||
>>> relative_time(now, ndigits=1)
|
>>> relative_time(now, ndigits=1)
|
||||||
'0 seconds ago'
|
'0 seconds ago'
|
||||||
>>> relative_time(now - timedelta(days=1, seconds=36000), ndigits=1)
|
>>> relative_time(now - timedelta(days=1, seconds=36000), ndigits=1)
|
||||||
|
@ -208,3 +217,184 @@ def relative_time(d, other=None, ndigits=0):
|
||||||
if drt < 0:
|
if drt < 0:
|
||||||
phrase = 'from now'
|
phrase = 'from now'
|
||||||
return '%g %s %s' % (abs(drt), unit, phrase)
|
return '%g %s %s' % (abs(drt), unit, phrase)
|
||||||
|
|
||||||
|
|
||||||
|
# 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')
|
||||||
|
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
|
@ -1,206 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""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). For timezones
|
|
||||||
beyond these, as well as a higher degree of accuracy, check out `pytz`_.
|
|
||||||
|
|
||||||
.. _pytz: https://pypi.python.org/pypi/pytz
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
import time
|
|
||||||
from datetime import tzinfo, timedelta, datetime
|
|
||||||
|
|
||||||
# Basic timezones cribbed from etavta and Python docs.
|
|
||||||
|
|
||||||
ZERO = timedelta(0)
|
|
||||||
HOUR = timedelta(hours=1)
|
|
||||||
|
|
||||||
|
|
||||||
# copied from timeutils for tzutils independence:
|
|
||||||
def total_seconds(td):
|
|
||||||
"""For those with older versions of Python, a pure-Python
|
|
||||||
implementation of Python 2.7's :meth:`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
|
|
||||||
|
|
||||||
|
|
||||||
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')
|
|
||||||
|
|
||||||
|
|
||||||
class LocalTZInfo(tzinfo):
|
|
||||||
"""The ``LocalTZInfo`` type takes data available in the time module about
|
|
||||||
the local timezone and makes a practical tzinfo to represent the
|
|
||||||
timezone settings of the operating system.
|
|
||||||
"""
|
|
||||||
_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")
|
|
|
@ -58,7 +58,7 @@ a definite set of themes have emerged:
|
||||||
|
|
||||||
1. :mod:`~boltons.queueutils` - `heapq docs`_
|
1. :mod:`~boltons.queueutils` - `heapq docs`_
|
||||||
2. :mod:`~boltons.iterutils` - `itertools docs`_
|
2. :mod:`~boltons.iterutils` - `itertools docs`_
|
||||||
3. :mod:`~boltons.tzutils` - `datetime docs`_
|
3. :mod:`~boltons.timeutils` - `datetime docs`_
|
||||||
|
|
||||||
2. Reimplementations and tweaks of the standard library:
|
2. Reimplementations and tweaks of the standard library:
|
||||||
|
|
||||||
|
|
|
@ -104,4 +104,3 @@ Section listing
|
||||||
tbutils
|
tbutils
|
||||||
timeutils
|
timeutils
|
||||||
typeutils
|
typeutils
|
||||||
tzutils
|
|
||||||
|
|
|
@ -2,5 +2,46 @@
|
||||||
======================================
|
======================================
|
||||||
|
|
||||||
.. automodule:: boltons.timeutils
|
.. automodule:: boltons.timeutils
|
||||||
:members:
|
|
||||||
:undoc-members:
|
.. autofunction:: total_seconds
|
||||||
|
.. autofunction:: isoparse
|
||||||
|
.. autofunction:: parse_timedelta
|
||||||
|
.. autofunction:: total_seconds
|
||||||
|
.. autofunction:: relative_time
|
||||||
|
.. autofunction:: decimal_relative_time
|
||||||
|
|
||||||
|
General timezones
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
By default, :class:`datetime.datetime` objects are "naïve", meaning
|
||||||
|
they lack attached timezone information. These objects can be useful
|
||||||
|
for many operations, but many operations require timezone-aware
|
||||||
|
datetimes.
|
||||||
|
|
||||||
|
The two most important timezones in programming are Coordinated
|
||||||
|
Universal Time (`UTC`_) and the local timezone of the host running
|
||||||
|
your code. Boltons provides two :class:`datetime.tzinfo` subtypes for
|
||||||
|
working with them:
|
||||||
|
|
||||||
|
.. _UTC: https://en.wikipedia.org/wiki/Coordinated_Universal_Time
|
||||||
|
|
||||||
|
.. autoattribute:: boltons.timeutils.UTC
|
||||||
|
.. autodata:: boltons.timeutils.LocalTZ
|
||||||
|
|
||||||
|
.. autoclass:: boltons.timeutils.ConstantTZInfo
|
||||||
|
|
||||||
|
US timezones
|
||||||
|
------------
|
||||||
|
|
||||||
|
These four US timezones were implemented in the :mod:`datetime`
|
||||||
|
documentation and have been reproduced here in boltons for
|
||||||
|
convenience. More in-depth support is provided by `pytz`_.
|
||||||
|
|
||||||
|
.. _pytz: https://pypi.python.org/pypi/pytz
|
||||||
|
|
||||||
|
.. autoattribute:: boltons.timeutils.Eastern
|
||||||
|
.. autoattribute:: boltons.timeutils.Central
|
||||||
|
.. autoattribute:: boltons.timeutils.Mountain
|
||||||
|
.. autoattribute:: boltons.timeutils.Pacific
|
||||||
|
|
||||||
|
.. autoclass:: boltons.timeutils.USTimeZone
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
``tzutils`` - Barebone timezones
|
|
||||||
================================
|
|
||||||
|
|
||||||
.. automodule:: boltons.tzutils
|
|
||||||
|
|
||||||
General timezones
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
.. autoattribute:: boltons.tzutils.UTC
|
|
||||||
.. autodata:: boltons.tzutils.LocalTZ
|
|
||||||
|
|
||||||
.. autoclass:: boltons.tzutils.ConstantTZInfo
|
|
||||||
|
|
||||||
US timezones
|
|
||||||
------------
|
|
||||||
|
|
||||||
.. autoattribute:: boltons.tzutils.Eastern
|
|
||||||
.. autoattribute:: boltons.tzutils.Central
|
|
||||||
.. autoattribute:: boltons.tzutils.Mountain
|
|
||||||
.. autoattribute:: boltons.tzutils.Pacific
|
|
||||||
|
|
||||||
.. autoclass:: boltons.tzutils.USTimeZone
|
|
Loading…
Reference in New Issue