xoutil.future.datetime - Basic date and time types

This module extends the standard library’s datetime. You may use it as a drop-in replacement in many cases.

Avoid importing * from this module since could be different in Python 2.7 and Python 3.3.

In Pytnon versions <= 3 date format fails for several dates, for example date(1800, 1, 1).strftime("%Y"). So, classes date and datetime are redefined if that case.

This problem could be solved by redefining the strftime function in the time module, because it is used for all strftime methods; but (WTF), Python double checks the year (in each method and then again in time.strftime function).

xoutil.future.datetime.assure(obj)[source]

Make sure that a date or datetime instance is a safe version.

This is only a type checker alternative to standard library.

We added the following features.

xoutil.future.datetime.strfdelta(delta)[source]

Format a timedelta using a smart pretty algorithm.

Only two levels of values will be printed.

>>> def t(h, m):
...     return timedelta(hours=h, minutes=m)

>>> strfdelta(t(4, 56)) == '4h 56m'
True
xoutil.future.datetime.strftime(dt, fmt)[source]

Used as strftime method of date and datetime redefined classes.

Also could be used with standard instances.

xoutil.future.datetime.get_month_first(ref=None)[source]

Given a reference date, returns the first date of the same month. If ref is not given, then uses current date as the reference.

xoutil.future.datetime.get_month_last(ref=None)[source]

Given a reference date, returns the last date of the same month. If ref is not given, then uses current date as the reference.

xoutil.future.datetime.get_next_month(ref=None, lastday=False)[source]

Get the first or last day of the next month.

If lastday is False return the first date of the next month. Otherwise, return the last date.

The next month is computed with regards to a reference date. If ref is None, take the current date as the reference.

Examples:

>>> get_next_month(date(2017, 1, 23))
date(2017, 2, 1)
>>> get_next_month(date(2017, 1, 23), lastday=True)
date(2017, 2, 28)

New in version 1.7.3.

xoutil.future.datetime.is_full_month(start, end)[source]

Returns true if the arguments comprises a whole month.

class xoutil.future.datetime.flextime[source]
xoutil.future.datetime.daterange([start, ]stop[, step])[source]

Similar to standard ‘range’ function, but for date objets.

Returns an iterator that yields each date in the range of [start, stop), not including the stop.

If start is given, it must be a date (or datetime) value; and in this case only stop may be an integer meaning the numbers of days to look ahead (or back if stop is negative).

If only stop is given, start will be the first day of stop’s month.

step, if given, should be a non-zero integer meaning the numbers of days to jump from one date to the next. It defaults to 1. If it’s positive then stop should happen after start, otherwise no dates will be yielded. If it’s negative stop should be before start.

As with range, stop is never included in the yielded dates.

class xoutil.future.datetime.DateField(name, nullable=False)[source]

A simple descriptor for dates.

Ensures that assigned values must be parseable dates and parses them.

class xoutil.future.datetime.TimeSpan(start_date=None, end_date=None)[source]

A continuous span of time.

Time spans objects are iterable. They yield exactly two times: first the start date, and then the end date:

>>> ts = TimeSpan('2017-08-01', '2017-09-01')
>>> tuple(ts)
(date(2017, 8, 1), date(2017, 9, 1))

Time spans objects have two items:

>>> ts[0]
date(2017, 8, 1)

>>> ts[1]
date(2017, 9, 1)

>>> ts[:]
(date(2017, 8, 1), date(2017, 9, 1))

Two time spans are equal if their start_date and end_date are equal. When comparing a time span with a date, the date is coerced to a time span (from_date()).

Note

Comparing time spans with date time spans coerces the time span before comparing.

A time span with its start set to None is unbound to the past. A time span with its end set to None is unbound to the future. A time span that is both unbound to the past and the future contains all possible dates. A time span that is not unbound in any direction is bound.

A bound time span is valid if its start date comes before its end date.

Time spans can intersect, compared for containment of dates and by the subset/superset order operations (<=, >=). In this regard, they represent the set of dates between start and end, inclusively.

Warning

Time spans don’t implement the union or difference operations expected in sets because the difference/union of two span is not necessarily continuous.

classmethod from_date(date)[source]

Return a new time span that covers a single date.

past_unbound

True if the time span is not bound into the past.

future_unbound

True if the time span is not bound into the future.

unbound

True if the time span is unbound into the past or unbount into the future or both.

bound

True if the time span is not unbound.

valid

A bound time span is valid if it starts before it ends.

Unbound time spans are always valid.

__le__(other)[source]

True if other is a superset.

issubset()

An alias for __le__().

__ge__(other)[source]

True if other is a subset.

issuperset()

An alias for __ge__().

covers()

An alias for __ge__().

isdisjoint(other)[source]
overlaps(other)[source]

Test if the time spans overlaps.

__contains__(other)[source]

Test date other is in the time span.

__and__(other)[source]

Get the time span that is the intersection with another time span.

If two time spans don’t overlap, return EmptyTimeSpan.

If other is not a TimeSpan we try to create one. If other is a date, we create the TimeSpan that starts and end that very day. Other types are passed unchanged to the constructor.

When other is a DateTimeSpan, convert self to a date time span before doing the intersection.

__mul__()

An alias for __and__().

intersection(*others)[source]

Return self [& other1 & ...].

__lshift__(delta)[source]

Return the time span displaced to the past in delta.

Parameters:delta – The number of days to displace. It can be either an integer or a datetime.timedelta. The integer will be converted to timedelta(days=delta).

Note

Delta values that don’t amount to at least a day will be the same as 0.

New in version 1.8.2.

Warning

Python does have a boundaries for the dates it can represent, so displacing a TimeSpan can cause OverflowError.

__rshift__(delta)[source]

Return the time span displaced to the future in delta.

Parameters:delta – The number of days to displace. It can be either an integer or a datetime.timedelta. The integer will be converted to timedelta(days=delta).

Note

Delta values that don’t amount to at least a day will be the same as 0.

New in version 1.8.2.

Warning

Python does have a boundaries for the dates it can represent, so displacing a TimeSpan can cause OverflowError.

__len__()[source]

The amount of dates in the span.

Warning

If the time span is unbound this method returns NotImplemented. This will make python complain with a TypeError.

New in version 1.8.2.

diff(other)[source]

Return the two time spans which (combined) contain all the dates in self which are not in other.

Notice this method returns a tuple of exactly two items.

If other and self don’t overlap, return (self, EmptyTimeSpan).

If self <= other is True, return the tuple with the empty time span in both positions.

Otherwise self will have some dates which are not in other; there are possible three cases:

  1. other starts before or at self’s start date; return the empty time span and the time span containing the dates after other.end_date up to self.end_date
  2. other ends at or after self’s end date; return the dates from self.start_date up to the date before other.start_date and the empty time span.
  3. other is fully contained in self; return two non-empty time spans as in the previous cases.

New in version 1.9.7.

class xoutil.future.datetime.DateTimeSpan(start_datetime=None, end_datetime=None)[source]

A continuous span of time (with datetime at each boundary).

DateTimeSpan is a minor extension of TimeSpan, and is a subclass.

DateTimeSpan objects are iterable. They yield exactly two datetimes: first the start date, and then the end date:

>>> ts = DateTimeSpan('2017-08-01 11:00', '2017-09-01 23:00')
>>> tuple(ts)
(datetime(2017, 8, 1, 11, 0), date(2017, 9, 1, 23, 0))

The API of DateTimeSpan is just the natural transformation of the API of TimeSpan.

The start_date and end_date attributes are interlocked with the start_datetime and end_datetime. By changing start_date, you also change start_datetime with the same date at 00:00 without tzinfo. By setting start_datetime you also update start_date. By setting end_date you also update end_datetime with the same date at 23:59:59 without tzinfo.

New in version 1.9.7.

Warning

DateTimeSpan is provided on a provisional basis. Future releases can change its API or remove it completely.

classmethod from_datetime(dt)[source]

Return a new date time span that covers a single datetime.

If dt is actually a date, the start_datetime will be at ‘00:00:00’ and the end_datetime will be at ‘23:59:59’.

classmethod from_timespan(ts)[source]

Return a new date time span from a timespan.

Notice the start datetime will be set at ‘00:00:00’ and the end datetime at ‘23:59:59’.

If ts is already a DateTimeSpan, return it unchanged.

past_unbound

True if the time span is not bound into the past.

future_unbound

True if the time span is not bound into the future.

unbound

True if the time span is unbound into the past or unbount into the future or both.

bound

True if the time span is not unbound.

valid

A bound time span is valid if it starts before it ends.

Unbound time spans are always valid.

__le__(other)[source]

True if other is a superset.

issubset()

An alias for __le__().

__ge__(other)[source]

True if other is a subset.

issuperset()

An alias for __ge__().

covers()

An alias for __ge__().

isdisjoint(other)[source]
overlaps(other)[source]

Test if the time spans overlaps.

__contains__(other)[source]

Test if datetime other is in the datetime span.

If other is a date, we convert it to a naive datetime at midnight (00:00:00).

__and__(other)[source]

Get the date time span that is the intersection with another time span.

If two time spans don’t overlap, return the object EmptyTimeSpan.

If other is not a DateTimeSpan we try to create one. If other is a date/datetime, we create use from_datetime(). If other is TimeSpan we use from_timespan(). Other types are passed unchanged to the constructor.

__mul__()

An alias for __and__().

intersection(*others)[source]

Return self [& other1 & ...].

__lshift__(delta)[source]

Return the date time span displaced to the past in delta.

Parameters:delta – The number of days to displace. It can be either an integer or a datetime.timedelta. The integer will be converted to timedelta(days=delta).

Warning

Python does have a boundaries for the dates it can represent, so displacing can cause OverflowError.

__rshift__(delta)[source]

Return the date time span displaced to the future in delta.

Parameters:delta – The number of days to displace. It can be either an integer or a datetime.timedelta. The integer will be converted to timedelta(days=delta).

Warning

Python does have a boundaries for the dates it can represent, so displacing can cause OverflowError.

__len__()

The amount of dates in the span.

Warning

If the time span is unbound this method returns NotImplemented. This will make python complain with a TypeError.

New in version 1.8.2.

diff(other)[source]

Return the two datetime spans which (combined) contain all the seconds in self which are not in other.

Notice this method returns a tuple of exactly two items.

If other and self don’t overlap, return (self, EmptyTimeSpan).

If self <= other is True, return the tuple with the empty time span in both positions.

Otherwise self will have some datetimes which are not in other; there are possible three cases:

  1. other starts before or at self’s start datetime; return the empty time span and the datetime span from the second after other.end_datetime up to self.end_datetime
  2. other ends at or after self’s end date; return the datetime span from self.start_datetime up to the second before other.start_datetime and the empty time span.
  3. other is fully contained in self; return two non-empty datetime spans as in the previous cases.
xoutil.future.datetime.EmptyTimeSpan

The empty time span. It’s not an instance of TimeSpan but engage set-like operations: union, intersection, etc.

No date is a member of the empty time span. The empty time span is a proper subset of any time span. It’s only a superset of itself. It’s not a proper superset of any other time span nor itself.

This instance is a singleton.