Changes in the manner that date differences are represented and compared

svn: r11565
This commit is contained in:
Doug Blank 2009-01-04 17:44:33 +00:00
parent 2347aeeaeb
commit 61ca9201b5
3 changed files with 482 additions and 114 deletions

View File

@ -2,6 +2,7 @@
# Gramps - a GTK+/GNOME based genealogy program # Gramps - a GTK+/GNOME based genealogy program
# #
# Copyright (C) 2008 Donald N. Allingham # Copyright (C) 2008 Donald N. Allingham
# Copyright (C) 2009 Douglas S. Blank
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -248,7 +249,7 @@ class SimpleTable:
elif isinstance(item, gen.lib.Span): elif isinstance(item, gen.lib.Span):
text = str(item) text = str(item)
retval.append(text) retval.append(text)
self.row_sort_val(col, float(item)) self.row_sort_val(col, item)
else: else:
raise AttributeError, ("unknown object type: '%s': %s" % raise AttributeError, ("unknown object type: '%s': %s" %
(item, type(item))) (item, type(item)))

View File

@ -2,6 +2,7 @@
# Gramps - a GTK+/GNOME based genealogy program # Gramps - a GTK+/GNOME based genealogy program
# #
# Copyright (C) 2000-2007 Donald N. Allingham # Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2009 Douglas S. Blank
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -28,6 +29,7 @@
# #
#------------------------------------------------------------------------ #------------------------------------------------------------------------
from gettext import gettext as _ from gettext import gettext as _
from gettext import ngettext as _s
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
@ -70,62 +72,488 @@ class DateError(Exception):
return self.value return self.value
class Span: class Span:
""" Class used in date differences """ """
def __init__(self, *diff_tuple): Span is used to represent the difference between two dates for three
self.diff_tuple = tuple(diff_tuple) main purposes: sorting, ranking, and describing.
def __getitem__(self, pos): sort = (base day count, offset)
return self.diff_tuple[pos] minmax = (min days, max days)
"""
BEFORE = Config.get(Config.DATE_BEFORE_RANGE)
AFTER = Config.get(Config.DATE_AFTER_RANGE)
ABOUT = Config.get(Config.DATE_ABOUT_RANGE)
def __init__(self, date1, date2):
self.valid = (date1.sortval != 0 and date2.sortval != 0)
self.date1 = date1
self.date2 = date2
self.sort = (-9999, -9999)
self.minmax = (9999, -9999)
self.repr = None
self.precision = 2
self.negative = False
if self.valid:
if self.date1.calendar != Date.CAL_GREGORIAN:
self.date1 = self.date1.to_calendar("gregorian")
if self.date2.calendar != Date.CAL_GREGORIAN:
self.date2 = self.date2.to_calendar("gregorian")
if self.date1.sortval < self.date2.sortval:
self.date1 = date2
self.date2 = date1
self.negative = True
if self.date1.get_modifier() == Date.MOD_NONE:
if self.date2.get_modifier() == Date.MOD_NONE:
v = self.date1.sortval - self.date2.sortval
self.sort = (v, 0)
self.minmax = (v, v)
#self.repr = self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_BEFORE:
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.BEFORE)
self.minmax = (v - Span.BEFORE, v)
#self.repr = "more than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_AFTER:
v = self.date1.sortval - self.date2.sortval
self.sort = (v, Span.AFTER)
self.minmax = (v, v + Span.AFTER)
#self.repr = "less than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_ABOUT:
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.ABOUT)
self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
#self.repr = "about " + self._format(self._diff(self.date1, self.date2))
elif (self.date2.get_modifier() == Date.MOD_RANGE or
self.date2.get_modifier() == Date.MOD_SPAN):
start, stop = self.date2.get_start_stop_range()
start = Date(*start)
stop = Date(*stop)
v1 = self.date1.sortval - stop.sortval # min
v2 = self.date1.sortval - start.sortval # max
self.sort = (v1, v2 - v1)
self.minmax = (v1, v2)
#self.repr = ("between " + self._format(self._diff(self.date1, stop)) +
# " and " + self._format(self._diff(self.date1, start)))
elif self.date1.get_modifier() == Date.MOD_BEFORE: # BEFORE----------------------------
if self.date2.get_modifier() == Date.MOD_NONE:
v = self.date1.sortval - self.date2.sortval
self.sort = (v, 0)
self.minmax = (0, v)
#self.repr = "less than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_BEFORE:
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.BEFORE)
self.minmax = (v, v + Span.BEFORE)
#self.repr = "more than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_AFTER:
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.AFTER)
self.minmax = (0, v)
#self.repr = "less than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_ABOUT:
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.ABOUT)
self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
#self.repr = "about " + self._format(self._diff(self.date1, self.date2))
elif (self.date2.get_modifier() == Date.MOD_RANGE or
self.date2.get_modifier() == Date.MOD_SPAN):
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.ABOUT)
self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
#self.repr = "more than " + self._format(self._diff(self.date1, self.date2))
elif self.date1.get_modifier() == Date.MOD_AFTER: # AFTER----------------------------
if self.date2.get_modifier() == Date.MOD_NONE:
v = self.date1.sortval - self.date2.sortval
self.sort = (v, Span.AFTER)
self.minmax = (v, v + Span.AFTER)
#self.repr = "more than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_BEFORE:
v = self.date1.sortval - self.date2.sortval
self.sort = (v, Span.AFTER)
self.minmax = (v - Span.BEFORE, v + Span.AFTER)
#self.repr = "more than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_AFTER:
v = self.date1.sortval - self.date2.sortval
self.sort = (v, Span.AFTER)
self.minmax = (v, v + Span.AFTER)
#self.repr = "more than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_ABOUT:
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.ABOUT)
self.minmax = (v - Span.ABOUT, v + Span.AFTER)
#self.repr = "more than about " + self._format(self._diff(self.date1, self.date2))
elif (self.date2.get_modifier() == Date.MOD_RANGE or
self.date2.get_modifier() == Date.MOD_SPAN):
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.ABOUT)
self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
#self.repr = "more than " + self._format(self._diff(self.date1, self.date2))
elif self.date1.get_modifier() == Date.MOD_ABOUT: # ABOUT----------------------------
if self.date2.get_modifier() == Date.MOD_NONE:
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.ABOUT)
self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
#self.repr = "about " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_BEFORE:
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.BEFORE)
self.minmax = (v - Span.BEFORE, v + Span.ABOUT)
#self.repr = "more than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_AFTER:
v = self.date1.sortval - self.date2.sortval
self.sort = (v, Span.AFTER)
self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
#self.repr = "less than about " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_ABOUT:
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.ABOUT)
self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
#self.repr = "about " + self._format(self._diff(self.date1, self.date2))
elif (self.date2.get_modifier() == Date.MOD_RANGE or
self.date2.get_modifier() == Date.MOD_SPAN):
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.ABOUT)
self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
#self.repr = "about " + self._format(self._diff(self.date1, self.date2))
elif (self.date1.get_modifier() == Date.MOD_RANGE or
self.date1.get_modifier() == Date.MOD_SPAN): # SPAN----------------------------
if self.date2.get_modifier() == Date.MOD_NONE:
start, stop = self.date1.get_start_stop_range()
start = Date(*start)
stop = Date(*stop)
v1 = self.date2.sortval - start.sortval # min
v2 = self.date2.sortval - stop.sortval # max
self.sort = (v1, v2 - v1)
self.minmax = (v1, v2)
#self.repr = ("between " + self._format(self._diff(start, self.date2)) +
# " and " + self._format(self._diff(stop, self.date2)))
elif self.date2.get_modifier() == Date.MOD_BEFORE:
v = self.date1.sortval - self.date2.sortval
self.sort = (v, Span.BEFORE)
self.minmax = (v - Span.BEFORE, v + Span.BEFORE)
#self.repr = "more than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_AFTER:
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.AFTER)
self.minmax = (v - Span.AFTER, v + Span.AFTER)
#self.repr = "less than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_ABOUT:
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.ABOUT)
self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
#self.repr = "about " + self._format(self._diff(self.date1, self.date2))
elif (self.date2.get_modifier() == Date.MOD_RANGE or
self.date2.get_modifier() == Date.MOD_SPAN):
start1, stop1 = self.date1.get_start_stop_range()
start2, stop2 = self.date2.get_start_stop_range()
start1 = Date(*start1)
start2 = Date(*start2)
stop1 = Date(*stop1)
stop2 = Date(*stop2)
v1 = start1.sortval - stop2.sortval # min
v2 = stop1.sortval - start2.sortval # max
self.sort = (v1, v2 - v1)
self.minmax = (v1, v2)
#self.repr = ("between " + self._format(self._diff(start1, stop2)) +
# " and " + self._format(self._diff(stop1, start2)))
def is_valid(self): def is_valid(self):
return True return self.valid
def __repr__(self):
if self.diff_tuple == (-1, -1, -1): return _("unknown")
retval = ""
if self.diff_tuple[0] != 0:
retval += (_("%d years") % self.diff_tuple[0])
if self.diff_tuple[1] != 0:
if retval != "":
retval += ", "
retval += (_("%d months") % self.diff_tuple[1])
if self.diff_tuple[2] != 0 and "," not in retval:
if retval != "":
retval += ", "
retval += (_("%d days") % self.diff_tuple[2])
if retval == "":
retval = "0 days"
return retval
def __int__(self): def __int__(self):
return int(self.diff_tuple[0] * 12 + if self.negative:
self.diff_tuple[1] return -self.sort[0]
) # number of months, for sorting else:
return self.sort[0]
def __cmp__(self, other):
if other is None:
return cmp(self.sort, (-9999, -9999))
elif self.negative:
return cmp((-self.sort[0], self.sort[1]), other.sort)
else:
return cmp(self.sort, other.sort)
def __repr__(self):
if self.repr is not None:
return self.repr
elif self.valid:
if self.date1.get_modifier() == Date.MOD_NONE:
if self.date2.get_modifier() == Date.MOD_NONE:
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, 0)
#self.minmax = (v, v)
self.repr = self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_BEFORE:
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, -Span.BEFORE)
#self.minmax = (v - Span.BEFORE, v)
self.repr = "more than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_AFTER:
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, Span.AFTER)
#self.minmax = (v, v + Span.AFTER)
self.repr = "less than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_ABOUT:
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, -Span.ABOUT)
#self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
self.repr = "about " + self._format(self._diff(self.date1, self.date2))
elif (self.date2.get_modifier() == Date.MOD_RANGE or
self.date2.get_modifier() == Date.MOD_SPAN):
start, stop = self.date2.get_start_stop_range()
start = Date(*start)
stop = Date(*stop)
#v1 = self.date1.sortval - stop.sortval # min
#v2 = self.date1.sortval - start.sortval # max
#self.sort = (v1, v2 - v1)
#self.minmax = (v1, v2)
self.repr = ("between " + self._format(self._diff(self.date1, stop)) +
" and " + self._format(self._diff(self.date1, start)))
elif self.date1.get_modifier() == Date.MOD_BEFORE: # BEFORE----------------------------
if self.date2.get_modifier() == Date.MOD_NONE:
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, 0)
#self.minmax = (0, v)
self.repr = "less than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_BEFORE:
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, -Span.BEFORE)
#self.minmax = (v, v + Span.BEFORE)
self.repr = "more than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_AFTER:
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, -Span.AFTER)
#self.minmax = (0, v)
self.repr = "less than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_ABOUT:
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, -Span.ABOUT)
#self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
self.repr = "about " + self._format(self._diff(self.date1, self.date2))
elif (self.date2.get_modifier() == Date.MOD_RANGE or
self.date2.get_modifier() == Date.MOD_SPAN):
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, -Span.ABOUT)
#self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
self.repr = "more than " + self._format(self._diff(self.date1, self.date2))
elif self.date1.get_modifier() == Date.MOD_AFTER: # AFTER----------------------------
if self.date2.get_modifier() == Date.MOD_NONE:
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, Span.AFTER)
#self.minmax = (v, v + Span.AFTER)
self.repr = "more than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_BEFORE:
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, Span.AFTER)
#self.minmax = (v - Span.BEFORE, v + Span.AFTER)
self.repr = "more than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_AFTER:
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, Span.AFTER)
#self.minmax = (v, v + Span.AFTER)
self.repr = "more than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_ABOUT:
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, -Span.ABOUT)
#self.minmax = (v - Span.ABOUT, v + Span.AFTER)
self.repr = "more than about " + self._format(self._diff(self.date1, self.date2))
elif (self.date2.get_modifier() == Date.MOD_RANGE or
self.date2.get_modifier() == Date.MOD_SPAN):
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, -Span.ABOUT)
#self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
self.repr = "more than " + self._format(self._diff(self.date1, self.date2))
elif self.date1.get_modifier() == Date.MOD_ABOUT: # ABOUT----------------------------
if self.date2.get_modifier() == Date.MOD_NONE:
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, -Span.ABOUT)
#self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
self.repr = "about " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_BEFORE:
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, -Span.BEFORE)
#self.minmax = (v - Span.BEFORE, v + Span.ABOUT)
self.repr = "more than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_AFTER:
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, Span.AFTER)
#self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
self.repr = "less than about " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_ABOUT:
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, -Span.ABOUT)
#self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
self.repr = "about " + self._format(self._diff(self.date1, self.date2))
elif (self.date2.get_modifier() == Date.MOD_RANGE or
self.date2.get_modifier() == Date.MOD_SPAN):
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, -Span.ABOUT)
#self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
self.repr = "about " + self._format(self._diff(self.date1, self.date2))
elif (self.date1.get_modifier() == Date.MOD_RANGE or
self.date1.get_modifier() == Date.MOD_SPAN): # SPAN----------------------------
if self.date2.get_modifier() == Date.MOD_NONE:
start, stop = self.date1.get_start_stop_range()
start = Date(*start)
stop = Date(*stop)
#v1 = self.date2.sortval - start.sortval # min
#v2 = self.date2.sortval - stop.sortval # max
#self.sort = (v1, v2 - v1)
#self.minmax = (v1, v2)
self.repr = ("between " + self._format(self._diff(start, self.date2)) +
" and " + self._format(self._diff(stop, self.date2)))
elif self.date2.get_modifier() == Date.MOD_BEFORE:
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, Span.BEFORE)
#self.minmax = (v - Span.BEFORE, v + Span.BEFORE)
self.repr = "more than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_AFTER:
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, -Span.AFTER)
#self.minmax = (v - Span.AFTER, v + Span.AFTER)
self.repr = "less than " + self._format(self._diff(self.date1, self.date2))
elif self.date2.get_modifier() == Date.MOD_ABOUT:
#v = self.date1.sortval - self.date2.sortval
#self.sort = (v, -Span.ABOUT)
#self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
self.repr = "about " + self._format(self._diff(self.date1, self.date2))
elif (self.date2.get_modifier() == Date.MOD_RANGE or
self.date2.get_modifier() == Date.MOD_SPAN):
start1, stop1 = self.date1.get_start_stop_range()
start2, stop2 = self.date2.get_start_stop_range()
start1 = Date(*start1)
start2 = Date(*start2)
stop1 = Date(*stop1)
stop2 = Date(*stop2)
#v1 = start1.sortval - stop2.sortval # min
#v2 = stop1.sortval - start2.sortval # max
#self.sort = (v1, v2 - v1)
#self.minmax = (v1, v2)
self.repr = ("between " + self._format(self._diff(start1, stop2)) +
" and " + self._format(self._diff(stop1, start2)))
return self.repr
else:
return _("unknown")
def __float__(self):
return float(self.diff_tuple[0] * 12 +
self.diff_tuple[1] +
self.diff_tuple[2]/31.0
) # number of months, for sorting
def __eq__(self, other): def __eq__(self, other):
"""
For comparing of Spans. Uses the sort tuple pair.
"""
if other is None: if other is None:
return False return False
return self.diff_tuple == other.diff_tuple return self.sort == other.sort
def __lt__(self, other): def __lt__(self, other):
"""
For less-than comparing of Spans. Uses the sort tuple pair.
"""
if other is None: if other is None:
return False return False
return self.diff_tuple < other.diff_tuple return self.sort < other.sort
def __gt__(self, other): def __gt__(self, other):
"""
For greater-than comparing of Spans. Uses the sort tuple pair.
"""
if other is None: if other is None:
return False return True
return self.diff_tuple > other.diff_tuple return self.sort > other.sort
def __len__(self): def format(self, precision=2):
return len(self.diff_tuple) """
Force a string representation at a level of precision.
1 = only most significant level (year, month, day)
2 = only most two significant levels (year, month, day)
3 = at most three items of signifance (year, month, day)
"""
self.repr = None
self.precision = precision
return repr(self)
def _format(self, diff_tuple):
if diff_tuple == (-1, -1, -1): return _("unknown")
retval = ""
detail = 0
if diff_tuple[0] != 0:
retval += (_s("%d year", "%d years", diff_tuple[0]) % diff_tuple[0])
detail += 1
if self.precision == detail:
return retval
if diff_tuple[1] != 0:
if retval != "":
retval += ", "
retval += (_s("%d month", "%d months", diff_tuple[1]) % diff_tuple[1])
detail += 1
if self.precision == detail:
return retval
if diff_tuple[2] != 0:
if retval != "":
retval += ", "
retval += (_s("%d day", "%d days", diff_tuple[2]) % diff_tuple[2])
detail += 1
if self.precision == detail:
return retval
if retval == "":
retval = _("0 days")
return retval
def _diff(self, date1, date2):
# We should make sure that Date2 + tuple -> Date1 and
# Date1 - tuple -> Date2
d1 = [i or 1 for i in date1.get_ymd()]
d2 = [i or 1 for i in date2.get_ymd()]
# d1 - d2 (1998, 12, 32) - (1982, 12, 15)
# days:
if d2[2] > d1[2]:
# months:
if d2[1] > d1[1]:
d1[0] -= 1
d1[1] += 12
d1[1] -= 1
d1[2] += 31
# months:
if d2[1] > d1[1]:
d1[0] -= 1 # from years
d1[1] += 12 # to months
days = d1[2] - d2[2]
months = d1[1] - d2[1]
years = d1[0] - d2[0]
if days > 31:
months += days / 31
days = days % 31
if months > 12:
years += months / 12
months = months % 12
# estimate: (years, months, days)
# Check transitivity:
if date1.is_full() and date2.is_full():
eDate = date1 - (years, months, days)
if eDate < date2: # too small, strictly less than
diff = 0
while eDate << date2 and diff < 60:
diff += 1
eDate = eDate + (0, 0, diff)
if diff == 60:
return (-1, -1, -1)
if self.negative:
return (-years, -months, -(days - diff))
else:
return (years, months, days - diff)
elif eDate > date2:
diff = 0
while eDate >> date2 and diff > -60:
diff -= 1
eDate = eDate - (0, 0, abs(diff))
if diff == -60:
return (-1, -1, -1)
if self.negative:
return (-years, -months, -(days + diff))
else:
return (years, months, days + diff)
if self.negative:
return (-years, -months, -days)
else:
return (years, months, days)
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
@ -349,76 +777,8 @@ class Date:
return self.copy_offset_ymd(-other) return self.copy_offset_ymd(-other)
elif isinstance(other, (tuple, list)): # Date - (y, m, d) -> Date elif isinstance(other, (tuple, list)): # Date - (y, m, d) -> Date
return self.copy_offset_ymd(*[-i for i in other]) return self.copy_offset_ymd(*[-i for i in other])
elif isinstance(other, type(self)): # Date1 - Date2 -> tuple elif isinstance(other, type(self)): # Date1 - Date2 -> tuple
# We should make sure that Date2 + tuple -> Date1 and return Span(self, other)
# Date1 - tuple -> Date2
date1 = self
date2 = other
negative = False
if date1.calendar != Date.CAL_GREGORIAN:
date1 = date1.to_calendar("gregorian")
if date2.calendar != Date.CAL_GREGORIAN:
date2 = date2.to_calendar("gregorian")
if date1.sortval == 0 or date2.sortval == 0:
return Span(-1, -1, -1)
d1 = [i or 1 for i in date1.get_ymd()]
d2 = [i or 1 for i in date2.get_ymd()]
if d1 < d2:
d1, d2 = d2, d1
date1, date2 = date2, date1
negative = True
# d1 - d2 (1998, 12, 32) - (1982, 12, 15)
# days:
if d2[2] > d1[2]:
# months:
if d2[1] > d1[1]:
d1[0] -= 1
d1[1] += 12
d1[1] -= 1
d1[2] += 31
# months:
if d2[1] > d1[1]:
d1[0] -= 1 # from years
d1[1] += 12 # to months
days = d1[2] - d2[2]
months = d1[1] - d2[1]
years = d1[0] - d2[0]
if days > 31:
months += days / 31
days = days % 31
if months > 12:
years += months / 12
months = months % 12
# estimate: (years, months, days)
# Check transitivity:
eDate = date1 - (years, months, days)
if eDate < date2: # too small, strictly less than
diff = 0
while eDate << date2 and diff < 60:
diff += 1
eDate = eDate + (0, 0, diff)
if diff == 60:
return Span(-1, -1, -1)
if negative:
return Span(-years, -months, -(days - diff))
else:
return Span(years, months, days - diff)
elif eDate > date2:
diff = 0
while eDate >> date2 and diff > -60:
diff -= 1
eDate = eDate - (0, 0, abs(diff))
if diff == -60:
return Span(-1, -1, -1)
if negative:
return Span(-years, -months, -(days + diff))
else:
return Span(years, months, days + diff)
else:
if negative:
return Span(-years, -months, -days)
else:
return Span(years, months, days)
else: else:
raise AttributeError, "unknown date sub type: %s " % type(other) raise AttributeError, "unknown date sub type: %s " % type(other)
@ -1108,6 +1468,12 @@ class Date:
and self.get_year_valid() and self.get_month_valid() \ and self.get_year_valid() and self.get_month_valid() \
and self.get_day_valid() and self.get_day_valid()
def is_full(self):
"""
Return True if the date is fully specified.
"""
return (self.get_year_valid() and self.get_month_valid() and self.get_day_valid())
def get_ymd(self): def get_ymd(self):
""" """
Return (year, month, day). Return (year, month, day).

View File

@ -3,6 +3,7 @@
# #
# Copyright (C) 2000-2007 Donald N. Allingham # Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2007-2008 Brian G. Matherly # Copyright (C) 2007-2008 Brian G. Matherly
# Copyright (C) 2009 Douglas S. Blank
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -63,15 +64,15 @@ def run(database, document, date):
if (birth_date.get_valid() and birth_date < date and if (birth_date.get_valid() and birth_date < date and
birth_date.get_year() != 0 and birth_date.get_year() != 0 and
((death_date is None) or (death_date > date))): ((death_date is None) or (death_date > date))):
diff_tuple = (date - birth_date) diff_span = (date - birth_date)
if ((death_date is not None) or if ((death_date is not None) or
(death_date is None and (death_date is None and
diff_tuple[0] <= Config.get(Config.MAX_AGE_PROB_ALIVE))): int(diff_span) <= Config.get(Config.MAX_AGE_PROB_ALIVE) * 365)):
birth_str = str(diff_tuple) birth_str = str(diff_span)
birth_sort = int(diff_tuple) birth_sort = int(diff_span)
if birth_str != "": if birth_str != "":
stab.row(person, birth_str) stab.row(person, birth_str)
stab.row_sort_val(1, birth_sort) stab.row_sort_val(1, diff_span)
matches += 1 matches += 1
sdoc.paragraph("\n%d matches.\n" % matches) sdoc.paragraph("\n%d matches.\n" % matches)
stab.write(sdoc) stab.write(sdoc)