timeutils - datetime additions

Python’s 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 datetime module’s documentation describes how to create a datetime-compatible 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, UTC (aka GMT) and 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`_.

boltons.timeutils.daterange(start, stop, step=1, inclusive=False)[source]

In the spirit of range() and xrange(), the daterange generator that yields a sequence of 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.

Parameters:
  • 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 int number of days, a datetime.timedelta, or a 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.

boltons.timeutils.isoparse(iso_str)[source]

Parses the limited subset of ISO8601-formatted time strings as returned by 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.

boltons.timeutils.parse_timedelta(text)[source]

Robustly parses a short text description of a time period into a datetime.timedelta. Supports weeks, days, hours, minutes, and seconds, with or without decimal points:

Parameters:

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
boltons.timeutils.strpdate(string, format)[source]

Parse the date string according to the format in format. Returns a date object. Internally, 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.

Parameters:
  • string (str) – The date string to be parsed.

  • format (str) – The strptime-style date format string.

Returns:

datetime.date

>>> 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)
boltons.timeutils.total_seconds()

Total seconds in the duration.

boltons.timeutils.dt_to_timestamp(dt)[source]

Converts from a datetime object to an integer timestamp, suitable interoperation with time.time() and other Epoch-based timestamps.

>>> timestamp = int(time.time())
>>> utc_dt = datetime.fromtimestamp(timestamp, timezone.utc)
>>> timestamp - dt_to_timestamp(utc_dt)
0.0

dt_to_timestamp supports both timezone-aware and naïve datetime objects. Note that it assumes naïve datetime objects are implied UTC, such as those generated with datetime.datetime.utcnow(). If your datetime objects are local time, such as those generated with datetime.datetime.now(), first convert it using the datetime.datetime.replace() method with tzinfo= LocalTZ object in this module, then pass the result of that to dt_to_timestamp.

boltons.timeutils.relative_time(d, other=None, ndigits=0)[source]

Get a string representation of the difference between two datetime objects or one datetime and the current time. Handles past and future times.

Parameters:
  • d (datetime) – The first datetime object.

  • other (datetime) – An optional second datetime object. If unset, defaults to the current time as determined 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'
boltons.timeutils.decimal_relative_time(d, other=None, ndigits=0, cardinalize=True)[source]

Get a tuple representing the relative time difference between two datetime objects or one datetime and now.

Parameters:
  • d (datetime) – The first datetime object.

  • other (datetime) – An optional second datetime object. If unset, defaults to the current time as determined 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:

A tuple of the float difference and

respective unit of time, pluralized if appropriate and cardinalize is set to True.

Return type:

(float, str)

Unlike 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')

General timezones

By default, 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 datetime.tzinfo subtypes for working with them:

Note

These days, Python has a built-in UTC, and the UTC tzinfo here, while equivalent, is just for backwards compat.

timeutils.UTC = ConstantTZInfo(name='UTC', offset=datetime.timedelta(0))
boltons.timeutils.LocalTZ = LocalTZInfo()

The LocalTZInfo type takes data available in the time module about the local timezone and makes a practical 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.

class boltons.timeutils.ConstantTZInfo(name='ConstantTZ', offset=datetime.timedelta(0))[source]

A tzinfo subtype whose offset remains constant (no daylight savings).

Parameters:

US timezones

These four US timezones were implemented in the datetime documentation and have been reproduced here in boltons for convenience. More in-depth support is provided by `dateutil`_ and pytz.

timeutils.Eastern = Eastern
timeutils.Central = Central
timeutils.Mountain = Mountain
timeutils.Pacific = Pacific
class boltons.timeutils.USTimeZone(hours, reprname, stdname, dstname)[source]

Copied directly from the Python docs, the USTimeZone is a datetime.tzinfo subtype used to create the Eastern, Central, Mountain, and Pacific tzinfo types.