[Python-ideas] datetime: Support infinity
Yawar Amin
yawar.amin at gmail.com
Tue Jan 27 03:59:56 CET 2015
Hi Thomas,
On 2015-01-26 03:24, Thomas Güttler wrote:
> [...]
> I don't know the internals of the datetime module. I guess it is not
> possible to support infinity.
>
> What do you think?
I think it's a great idea to support infinity dates in Python (in fact,
in any modern date handling library). If I read you right, the problem
with mapping back to Postgres is that infinity dates are being
represented in-band in Python, so they get mapped to non-infinite dates
in Postgres.
The solution is to represent infinity dates as out-of-band values. My
take on this is to represent them as subtypes of datetime and handle
those subtypes appropriately. A rough (but working) sketch of the idea:
import datetime as dt
class datetime_ext(dt.datetime):
def __new__(cls, *args, **kwargs):
return dt.datetime.__new__(cls, *args, **kwargs)
# Getting the infinity dates.
@staticmethod
def pos_inf(): return datetime_inf(1)
@staticmethod
def neg_inf(): return datetime_inf(-1)
# More fun names.
@staticmethod
def big_bang(): return datetime_ext.neg_inf()
@staticmethod
def big_crunch(): return datetime_ext.pos_inf()
# Now the fun part.
def _are_we_inf(self, other):
return (
isinstance(self, datetime_inf),
isinstance(other, datetime_inf)
)
def __lt__(self, other):
awi = self._are_we_inf(other)
if awi == (True, True): return self.sign < other.sign
elif awi == (False, True): return other.sign > 0
elif awi == (True, False): return self.sign < 0
else: return self < other
def __gt__(self, other):
awi = self._are_we_inf(other)
if awi == (True, True): return self.sign > other.sign
elif awi == (False, True): return other.sign < 0
elif awi == (True, False): return self.sign > 0
else: return self > other
def __eq__(self, other):
awi = self._are_we_inf(other)
if awi == (True, True): return self.sign == other.sign
elif awi == (False, False): return self == other
else: return False
def __ne__(self, other): return not (self == other)
def __le__(self, other): return (self < other) or (self == other)
def __ge__(self, other): return (self > other) or (self == other)
class datetime_inf(datetime_ext):
def __new__(cls, sign):
# The numbers passed in to the constructor are meaningless; they
# should never be used.
retval = datetime_ext.__new__(cls, 1, 1, 1)
retval.sign = sign
return retval
def _raise_err(self): raise TypeError("Infinity date")
def date(self): return datetime_inf(self.sign)
def time(self): _raise_err()
def timetz(self): _raise_err()
def replace(self): _raise_err()
def astimezone(self): _raise_err()
# ... all the others ...
# All True:
print(datetime_ext.big_bang() == datetime_ext.big_bang())
print(datetime_ext.big_crunch() == datetime_ext.big_crunch())
print(datetime_ext.big_bang() < datetime_ext.big_crunch())
print(datetime_ext.big_crunch() > datetime_ext.big_bang())
print(datetime_ext.big_bang() < dt.datetime.today())
print(datetime_ext.big_crunch() > dt.datetime.today())
# Added bonuses (boni?):
print(dt.datetime.max < datetime_ext.big_crunch())
print(dt.datetime.min > datetime_ext.big_bang())
So the basic idea here is to override the comparison methods to treat
the datetime_inf type specially. The implementation of datetime_inf
isn't particularly elegant, but I think it works for its intended
purpose.
Now with these, I'm pretty sure you can write an InfDateWrapper class
that checks for datetime_ext.big_bang() and datetime_ext.big_crunch()
and returns the corresponding Postgres '-infinity::date' and
'infinity::date'; and that the mapping will be fully bidirectional.
And as I said, I believe something like this should be added to the
Python stdlib. If no one has a better implementation I'll start working
on a proposal.
Regards,
Yawar
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 834 bytes
Desc: OpenPGP digital signature
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20150126/b11b5ea7/attachment.sig>
More information about the Python-ideas
mailing list