7034,7045,7065: back-merge my fixes from trunk

Back-merge from trunk changes to date.py and date_test.py
from the following commits (cumulative, clean apply).

Tests pass (but need to block the CAL_FRENCH on date_test.py:199,
because of bug# 7068 -- skipping it wasn't back-ported in this commit as
it is about the fully fixed issues only!)

	commit fa49752824bd58802773439b35faa39f2d34b151
	Author: Vassilii Khachaturov <vassilii@tarunz.org>
	Date:   Sat Sep 14 15:44:04 2013 +0000

		provide sensible defautls for all Date.set params

		git-svn-id: svn+ssh://svn.code.sf.net/p/gramps/code/trunk@23126 4ae1f11a-8b86-4847-b8af-ab372f36d1fd

	commit 3f32597699f3b372324ad87e6f7a04abac6d19e7
	Author: Vassilii Khachaturov <vassilii@tarunz.org>
	Date:   Sat Sep 14 15:11:09 2013 +0000

		7045: Setting an invalid date does not raise

		do the sanity checks on a separate date object,
		so that the uncertainty expressed with 0 d/m isn't removed

		git-svn-id: svn+ssh://svn.code.sf.net/p/gramps/code/trunk@23124 4ae1f11a-8b86-4847-b8af-ab372f36d1fd

	commit 12edf7e97626e01931c4063b2d94bec3b299a2ed
	Author: Vassilii Khachaturov <vassilii@tarunz.org>
	Date:   Sat Sep 14 14:23:58 2013 +0000

		7065: Calendar conversion broken for negative date

		fixed, repro steps work as expected now
		date_test still broken due to further blocking issues,
		see #7045

		git-svn-id: svn+ssh://svn.code.sf.net/p/gramps/code/trunk@23123 4ae1f11a-8b86-4847-b8af-ab372f36d1fd

	commit 091d4461e9715ab06f1ef6ab3b67517d6608daf3
	Author: Vassilii Khachaturov <vassilii@tarunz.org>
	Date:   Sat Sep 14 13:24:40 2013 +0000

		7045: Date.set on invalid date does not raise

		refactor _zero_adjust_ymd out of 3 cut-and-paste cases
		the bug with the code inside it remains -- the negative years
		should not be clamped to positive ones!!!!

		git-svn-id: svn+ssh://svn.code.sf.net/p/gramps/code/trunk@23122 4ae1f11a-8b86-4847-b8af-ab372f36d1fd

	commit 5987046ac4cac407a4be506da9242f7a5000d878
	Author: Vassilii Khachaturov <vassilii@tarunz.org>
	Date:   Sat Sep 14 13:00:19 2013 +0000

		7045: Date.set on invalid date does not raise

		Now it does, but another test breaks:

		Traceback (most recent call last):
		  File "/usr/lib/python2.7/unittest/loader.py", line 252, in _find_tests
			module = self._get_module_from_name(name)
		  File "/usr/lib/python2.7/unittest/loader.py", line 230, in _get_module_from_name
			__import__(name)
		  File "/home/vassilii/Gramps/gramps/gen/lib/test/date_test.py", line 136, in <module>
			d.set(quality,modifier,calendar,(4,11,-90,False),"Text comment")
		  File "/home/vassilii/Gramps/gramps/gen/lib/date.py", line 1600, in set
			format(original, value))
		DateError: Invalid year -90 passed in value (4, 11, -90, False)

		because the corresponding year gets adjusted from -90 to 1...

		git-svn-id: svn+ssh://svn.code.sf.net/p/gramps/code/trunk@23121 4ae1f11a-8b86-4847-b8af-ab372f36d1fd

	commit d8876cceb64629ce0a025ff714e4875768ab88a6
	Author: Vassilii Khachaturov <vassilii@tarunz.org>
	Date:   Sat Sep 14 11:50:58 2013 +0000

		7034: fix test_copy_ymd_preserves_orig

		broken in r23083

		git-svn-id: svn+ssh://svn.code.sf.net/p/gramps/code/trunk@23120 4ae1f11a-8b86-4847-b8af-ab372f36d1fd

	commit 7c163636c8e48149a5b09c211ff3dc146ebd84b2
	Author: Vassilii Khachaturov <vassilii@tarunz.org>
	Date:   Tue Sep 10 17:19:16 2013 +0000

		7034: add remove_stop_date parameter

		git-svn-id: svn+ssh://svn.code.sf.net/p/gramps/code/trunk@23083 4ae1f11a-8b86-4847-b8af-ab372f36d1fd

	commit b45e20da3bd67d864420f99cf59fbb9929c58851
	Author: Vassilii Khachaturov <vassilii@tarunz.org>
	Date:   Mon Sep 9 19:31:13 2013 +0000

		7034: probably_alive() failing when no birth-death

		further refactoring of set_.../set2_... common code
		added accessor get_stop_ymd analogous to get_ymd

		git-svn-id: svn+ssh://svn.code.sf.net/p/gramps/code/trunk@23068 4ae1f11a-8b86-4847-b8af-ab372f36d1fd

	commit f13a3fc23e7f0763c49e605b428b6a175c3f9eeb
	Author: Vassilii Khachaturov <vassilii@tarunz.org>
	Date:   Mon Sep 9 19:31:00 2013 +0000

		7034: probably_alive() failing when no birth-death

		docstring update

		git-svn-id: svn+ssh://svn.code.sf.net/p/gramps/code/trunk@23067 4ae1f11a-8b86-4847-b8af-ab372f36d1fd

	commit 9ee312d7ed02520b99d2ca1b28f75c87846aa3c6
	Author: Vassilii Khachaturov <vassilii@tarunz.org>
	Date:   Sun Sep 8 19:35:15 2013 +0000

		refactor test

		git-svn-id: svn+ssh://svn.code.sf.net/p/gramps/code/trunk@23059 4ae1f11a-8b86-4847-b8af-ab372f36d1fd

	commit 07ca997ebd885ad4d1b205907a00509099ac8f9a
	Author: Vassilii Khachaturov <vassilii@tarunz.org>
	Date:   Sun Sep 8 19:23:23 2013 +0000

		consistency between offset and non-offset setters

		added ugly parameter _update2 to set_yr_mon_day, needs refactoring

		git-svn-id: svn+ssh://svn.code.sf.net/p/gramps/code/trunk@23058 4ae1f11a-8b86-4847-b8af-ab372f36d1fd

	commit 67a904c529642668fbe34bfc97ef2915278ecbdb
	Author: Vassilii Khachaturov <vassilii@tarunz.org>
	Date:   Sun Sep 8 19:23:12 2013 +0000

		fix set_yr_mon_day_offset for compound dates

		now calls set2_yr_mon_day_offset

		git-svn-id: svn+ssh://svn.code.sf.net/p/gramps/code/trunk@23057 4ae1f11a-8b86-4847-b8af-ab372f36d1fd

	commit 3db06c36d6449ec75cde49b433349cddad40d596
	Author: Vassilii Khachaturov <vassilii@tarunz.org>
	Date:   Sun Sep 8 19:23:02 2013 +0000

		refactor set_yr_mon_day and set2_yr_mon_day

		refactor common base

		git-svn-id: svn+ssh://svn.code.sf.net/p/gramps/code/trunk@23056 4ae1f11a-8b86-4847-b8af-ab372f36d1fd

	commit 4192680c72cc0028c22fa207fe3f1ff0940358b3
	Author: Vassilii Khachaturov <vassilii@tarunz.org>
	Date:   Sun Sep 8 19:22:52 2013 +0000

		raise DateError in set2_... if not is_compound()

		refactor Date to always use is_compound instead of repeating
		its logic everywhere

		git-svn-id: svn+ssh://svn.code.sf.net/p/gramps/code/trunk@23055 4ae1f11a-8b86-4847-b8af-ab372f36d1fd

	commit 44195ede18c5a887d4440b4132bd5321f76ce5ff
	Author: Vassilii Khachaturov <vassilii@tarunz.org>
	Date:   Sun Sep 8 19:22:40 2013 +0000

		Add some UT for Date.set2_... and fix bugs

		Cut and paste is evil ;-) fix bugs before I refactor the code...

		git-svn-id: svn+ssh://svn.code.sf.net/p/gramps/code/trunk@23054 4ae1f11a-8b86-4847-b8af-ab372f36d1fd

	commit 14f6e3a3f35e0ff7b67006bf4996ce63ae665098
	Author: Vassilii Khachaturov <vassilii@tarunz.org>
	Date:   Sun Sep 8 19:22:30 2013 +0000

		7034: probably_alive() failing when no birth-death

		docstring fix

		git-svn-id: svn+ssh://svn.code.sf.net/p/gramps/code/trunk@23053 4ae1f11a-8b86-4847-b8af-ab372f36d1fd

svn: r23156
This commit is contained in:
Vassilii Khachaturov 2013-09-17 18:58:06 +00:00
parent 75ca7e1f8c
commit 63f022348b
2 changed files with 237 additions and 118 deletions

View File

@ -122,8 +122,7 @@ class Span(object):
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.ABOUT)
self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
elif (self.date2.get_modifier() == Date.MOD_RANGE or
self.date2.get_modifier() == Date.MOD_SPAN):
elif self.date2.is_compound():
start, stop = self.date2.get_start_stop_range()
start = Date(*start)
stop = Date(*stop)
@ -148,8 +147,7 @@ class Span(object):
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.ABOUT)
self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
elif (self.date2.get_modifier() == Date.MOD_RANGE or
self.date2.get_modifier() == Date.MOD_SPAN):
elif self.date2.is_compound():
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.ABOUT)
self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
@ -170,8 +168,7 @@ class Span(object):
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.ABOUT)
self.minmax = (v - Span.ABOUT, v + Span.AFTER)
elif (self.date2.get_modifier() == Date.MOD_RANGE or
self.date2.get_modifier() == Date.MOD_SPAN):
elif self.date2.is_compound():
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.ABOUT)
self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
@ -192,13 +189,11 @@ class Span(object):
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.ABOUT)
self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
elif (self.date2.get_modifier() == Date.MOD_RANGE or
self.date2.get_modifier() == Date.MOD_SPAN):
elif self.date2.is_compound():
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.ABOUT)
self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
elif (self.date1.get_modifier() == Date.MOD_RANGE or
self.date1.get_modifier() == Date.MOD_SPAN): # SPAN----------------------------
elif self.date1.is_compound():
if self.date2.get_modifier() == Date.MOD_NONE:
start, stop = self.date1.get_start_stop_range()
start = Date(*start)
@ -219,8 +214,7 @@ class Span(object):
v = self.date1.sortval - self.date2.sortval
self.sort = (v, -Span.ABOUT)
self.minmax = (v - Span.ABOUT, v + Span.ABOUT)
elif (self.date2.get_modifier() == Date.MOD_RANGE or
self.date2.get_modifier() == Date.MOD_SPAN):
elif self.date2.is_compound():
start1, stop1 = self.date1.get_start_stop_range()
start2, stop2 = self.date2.get_start_stop_range()
start1 = Date(*start1)
@ -314,8 +308,7 @@ class Span(object):
_repr = trans_text("less than") + " " + fdate12
elif self.date2.get_modifier() == Date.MOD_ABOUT:
_repr = trans_text("age|about") + " " + fdate12p1
elif (self.date2.get_modifier() == Date.MOD_RANGE or
self.date2.get_modifier() == Date.MOD_SPAN):
elif self.date2.is_compound():
start, stop = self.date2.get_start_stop_range()
start = Date(*start)
stop = Date(*stop)
@ -330,8 +323,7 @@ class Span(object):
_repr = trans_text("less than") + " " + fdate12
elif self.date2.get_modifier() == Date.MOD_ABOUT:
_repr = trans_text("less than about") + " " + fdate12
elif (self.date2.get_modifier() == Date.MOD_RANGE or
self.date2.get_modifier() == Date.MOD_SPAN):
elif self.date2.is_compound():
_repr = trans_text("less than") + " " + fdate12
elif self.date1.get_modifier() == Date.MOD_AFTER: # AFTER----------------------------
if self.date2.get_modifier() == Date.MOD_NONE:
@ -342,8 +334,7 @@ class Span(object):
_repr = self._format((-1, -1 , -1))
elif self.date2.get_modifier() == Date.MOD_ABOUT:
_repr = trans_text("more than about") + " " + fdate12p1
elif (self.date2.get_modifier() == Date.MOD_RANGE or
self.date2.get_modifier() == Date.MOD_SPAN):
elif self.date2.is_compound():
_repr = trans_text("more than") + " " + fdate12
elif self.date1.get_modifier() == Date.MOD_ABOUT: # ABOUT----------------------------
if self.date2.get_modifier() == Date.MOD_NONE:
@ -354,11 +345,9 @@ class Span(object):
_repr = trans_text("less than about") + " " + fdate12p1
elif self.date2.get_modifier() == Date.MOD_ABOUT:
_repr = trans_text("age|about") + " " + fdate12p1
elif (self.date2.get_modifier() == Date.MOD_RANGE or
self.date2.get_modifier() == Date.MOD_SPAN):
elif self.date2.is_compound():
_repr = trans_text("age|about") + " " + fdate12p1
elif (self.date1.get_modifier() == Date.MOD_RANGE or
self.date1.get_modifier() == Date.MOD_SPAN): # SPAN----------------------------
elif self.date1.is_compound():
if self.date2.get_modifier() == Date.MOD_NONE:
start, stop = self.date1.get_start_stop_range()
start = Date(*start)
@ -371,8 +360,7 @@ class Span(object):
_repr = trans_text("less than") + " " + fdate12
elif self.date2.get_modifier() == Date.MOD_ABOUT:
_repr = trans_text("age|about") + " " + fdate12p1
elif (self.date2.get_modifier() == Date.MOD_RANGE or
self.date2.get_modifier() == Date.MOD_SPAN):
elif self.date2.is_compound():
start1, stop1 = self.date1.get_start_stop_range()
start2, stop2 = self.date2.get_start_stop_range()
start1 = Date(*start1)
@ -1045,7 +1033,7 @@ class Date(object):
(self.dateval[Date._POS_YR]) % 10,
self.dateval[Date._POS_MON],
self.dateval[Date._POS_DAY])
elif self.modifier == Date.MOD_RANGE or self.modifier == Date.MOD_SPAN:
elif self.is_compound():
val = "%04d-%02d-%02d - %04d-%02d-%02d" % (
self.dateval[Date._POS_YR], self.dateval[Date._POS_MON],
self.dateval[Date._POS_DAY], self.dateval[Date._POS_RYR],
@ -1208,7 +1196,7 @@ class Date(object):
of (0, 0, 0, False) is returned. Otherwise, a date of (DD, MM, YY, slash)
is returned. If slash is True, then the date is in the form of 1530/1.
"""
if self.modifier == Date.MOD_RANGE or self.modifier == Date.MOD_SPAN:
if self.is_compound():
val = self.dateval[4:8]
else:
val = Date.EMPTY
@ -1238,7 +1226,7 @@ class Date(object):
"""
Return the item specified.
"""
if self.modifier == Date.MOD_SPAN or self.modifier == Date.MOD_RANGE:
if self.is_compound():
val = self.dateval[index]
else:
val = 0
@ -1285,89 +1273,91 @@ class Date(object):
"""
self.newyear = value
def set_yr_mon_day(self, year, month, day):
def __set_yr_mon_day(self, year, month, day, pos_yr, pos_mon, pos_day):
dv = list(self.dateval)
dv[pos_yr] = year
dv[pos_mon] = month
dv[pos_day] = day
self.dateval = tuple(dv)
def set_yr_mon_day(self, year, month, day, remove_stop_date = None):
"""
Set the year, month, and day values.
@param remove_stop_date Required parameter for a compound date.
When True, the stop date is changed to the same date as well.
When False, the stop date is not changed.
"""
dv = list(self.dateval)
dv[Date._POS_YR] = year
dv[Date._POS_MON] = month
dv[Date._POS_DAY] = day
self.dateval = tuple(dv)
if self.is_compound() and remove_stop_date is None:
raise DateError("Required parameter remove_stop_date not set!")
self.__set_yr_mon_day(year, month, day,
Date._POS_YR, Date._POS_MON, Date._POS_DAY)
self._calc_sort_value()
if remove_stop_date and self.is_compound():
self.set2_yr_mon_day(year, month, day)
def _assert_compound(self):
if not self.is_compound():
raise DateError("Operation allowed for compound dates only!")
def set2_yr_mon_day(self, year, month, day):
"""
Set the year, month, and day values.
Set the year, month, and day values in the 2nd part of
a compound date (range or span).
"""
self._assert_compound()
self.__set_yr_mon_day(year, month, day,
Date._POS_RYR, Date._POS_RMON, Date._POS_RDAY)
def __set_yr_mon_day_offset(self, year, month, day, pos_yr, pos_mon, pos_day):
dv = list(self.dateval)
dv[Date._POS_RYR] = year
dv[Date._POS_RMON] = month
dv[Date._POS_RDAY] = day
if dv[pos_yr]:
dv[pos_yr] += year
elif year:
dv[pos_yr] = year
if dv[pos_mon]:
dv[pos_mon] += month
elif month:
if month < 0:
dv[pos_mon] = 1 + month
else:
dv[pos_mon] = month
# Fix if month out of bounds:
if month != 0: # only check if changed
if dv[pos_mon] == 0: # subtraction
dv[pos_mon] = 12
dv[pos_yr] -= 1
elif dv[pos_mon] < 0: # subtraction
dv[pos_yr] -= int((-dv[pos_mon]) // 12) + 1
dv[pos_mon] = (dv[pos_mon] % 12)
elif dv[pos_mon] > 12 or dv[pos_mon] < 1:
dv[pos_yr] += int(dv[pos_mon] // 12)
dv[pos_mon] = dv[pos_mon] % 12
self.dateval = tuple(dv)
self._calc_sort_value()
return (day != 0 or dv[pos_day] > 28)
def set_yr_mon_day_offset(self, year=0, month=0, day=0):
"""
Set the year, month, and day values by offset.
Offset the date by the given year, month, and day values.
"""
dv = list(self.dateval)
if dv[Date._POS_YR]:
dv[Date._POS_YR] += year
elif year:
dv[Date._POS_YR] = year
if dv[Date._POS_MON]:
dv[Date._POS_MON] += month
elif month:
if month < 0:
dv[Date._POS_MON] = 1 + month
else:
dv[Date._POS_MON] = month
# Fix if month out of bounds:
if month != 0: # only check if changed
if dv[Date._POS_MON] == 0: # subtraction
dv[Date._POS_MON] = 12
dv[Date._POS_YR] -= 1
elif dv[Date._POS_MON] < 0: # subtraction
dv[Date._POS_YR] -= int((-dv[Date._POS_MON]) // 12) + 1
dv[Date._POS_MON] = (dv[Date._POS_MON] % 12)
elif dv[Date._POS_MON] > 12 or dv[Date._POS_MON] < 1:
dv[Date._POS_YR] += int(dv[Date._POS_MON] // 12)
dv[Date._POS_MON] = dv[Date._POS_MON] % 12
self.dateval = tuple(dv)
self._calc_sort_value()
if day != 0 or dv[Date._POS_DAY] > 28:
self.set_yr_mon_day(*self.offset(day))
if self.__set_yr_mon_day_offset(year, month, day,
Date._POS_YR, Date._POS_MON, Date._POS_DAY):
self.set_yr_mon_day(*self.offset(day), remove_stop_date = False)
if self.is_compound():
self.set2_yr_mon_day_offset(year, month, day)
def set2_yr_mon_day_offset(self, year=0, month=0, day=0):
"""
Set the year, month, and day values by offset.
Set the year, month, and day values by offset in the 2nd part
of a compound date (range or span).
"""
dv = list(self.dateval)
if dv[Date._POS_RYR]:
dv[Date._POS_RYR] += year
elif year:
dv[Date._POS_RYR] = year
if dv[Date._POS_RMON]:
dv[Date._POS_RMON] += month
elif month:
if month < 0:
dv[Date._POS_RMON] = 1 + month
else:
dv[Date._POS_RMON] = month
# Fix if month out of bounds:
if month != 0: # only check if changed
if dv[Date._POS_RMON] == 0: # subtraction
dv[Date._POS_RMON] = 12
dv[Date._POS_RYR] -= 1
elif dv[Date._POS_RMON] < 0: # subtraction
dv[Date._POS_RYR] -= int((-dv[Date._POS_RMON]) / 12) + 1
dv[Date._POS_RMON] = (dv[Date._POS_RMON] % 12)
elif dv[Date._POS_RMON] > 12 or dv[Date._POS_RMON] < 1:
dv[Date._POS_RYR] += int(dv[Date._POS_RMON] / 12)
dv[Date._POS_RMON] = dv[Date._POS_RMON] % 12
self.dateval = tuple(dv)
if day != 0 or dv[Date._POS_RDAY] > 28:
self.set2_yr_mon_day(*self.offset(day))
self._assert_compound()
if self.__set_yr_mon_day_offset(year, month, day,
Date._POS_RYR, Date._POS_RMON, Date._POS_RDAY):
stop = Date(self.get_stop_ymd())
self.set2_yr_mon_day(*stop.offset(day))
def copy_offset_ymd(self, year=0, month=0, day=0):
"""
@ -1380,24 +1370,19 @@ class Date(object):
new_date = self
retval = Date(new_date)
retval.set_yr_mon_day_offset(year, month, day)
if (self.get_modifier() == Date.MOD_RANGE or
self.get_modifier() == Date.MOD_SPAN):
retval.set2_yr_mon_day_offset(year, month, day)
if orig_cal == 0:
return retval
else:
retval.convert_calendar(orig_cal)
return retval
def copy_ymd(self, year=0, month=0, day=0):
def copy_ymd(self, year=0, month=0, day=0, remove_stop_date=None):
"""
Return a Date copy with year, month, and day set.
@param remove_stop_date Same as in set_yr_mon_day.
"""
retval = Date(self)
retval.set_yr_mon_day(year, month, day)
if (self.get_modifier() == Date.MOD_RANGE or
self.get_modifier() == Date.MOD_SPAN):
retval.set2_yr_mon_day_offset(year, month, day)
retval.set_yr_mon_day(year, month, day, remove_stop_date)
return retval
def set_year(self, year):
@ -1502,30 +1487,52 @@ class Date(object):
"""
return self.text
def set(self, quality, modifier, calendar, value, text=None,
newyear=0):
def _zero_adjust_ymd(self, y, m, d):
year = y if y != 0 else 1
month = max(m, 1)
day = max(d, 1)
return (year, month, day)
def set(self, quality=None, modifier=None, calendar=None,
value=None,
text=None, newyear=0):
"""
Set the date to the specified value.
Parameters are::
quality - The date quality for the date (see get_quality
for more information)
for more information).
Defaults to the previous value for the date.
modified - The date modifier for the date (see get_modifier
for more information)
Defaults to the previous value for the date.
calendar - The calendar associated with the date (see
get_calendar for more information).
Defaults to the previous value for the date.
value - A tuple representing the date information. For a
non-compound date, the format is (DD, MM, YY, slash)
and for a compound date the tuple stores data as
(DD, MM, YY, slash1, DD, MM, YY, slash2)
Defaults to the previous value for the date.
text - A text string holding either the verbatim user input
or a comment relating to the date.
Defaults to the previous value for the date.
newyear - The newyear code, or tuple representing (month, day)
of newyear day.
of newyear day.
Defaults to 0.
The sort value is recalculated.
"""
if quality is None:
quality = self.quality
if modifier is None:
modifier = self.modifier
if calendar is None:
calendar = self.calendar
if value is None:
value = self.value
if modifier in (Date.MOD_NONE, Date.MOD_BEFORE,
Date.MOD_AFTER, Date.MOD_ABOUT) and len(value) < 4:
@ -1551,11 +1558,12 @@ class Date(object):
self.calendar = calendar
self.dateval = value
self.set_new_year(newyear)
year = max(value[Date._POS_YR], 1)
month = max(value[Date._POS_MON], 1)
day = max(value[Date._POS_DAY], 1)
year, month, day = self._zero_adjust_ymd(
value[Date._POS_YR],
value[Date._POS_MON],
value[Date._POS_DAY])
if year == month == 0 and day == 0:
if year == month == day == 0:
self.sortval = 0
else:
func = Date._calendar_convert[calendar]
@ -1593,6 +1601,32 @@ class Date(object):
d2.set_calendar(self.calendar)
d2_val = d2.sortval
self.sortval += (d1_val - d2_val) + 1
if modifier != Date.MOD_TEXTONLY:
sanity = Date(self)
sanity.convert_calendar(self.calendar, known_valid = False)
# We don't do the roundtrip conversion on self, becaue
# it would remove uncertainty on day/month expressed with zeros
# Did the roundtrip change the date value?!
if sanity.dateval != value:
# Maybe it is OK because of undetermined value adjustment?
zl = zip(sanity.dateval, value)
# Loop over all values present, whether compound or not
for d,m,y,sl in zip(*[iter(zl)]*4):
# each of d,m,y,sl is a pair from dateval and value, to compare
for adjusted,original in d,m:
if adjusted != original and not(original == 0 and adjusted == 1):
raise DateError("Invalid day/month {} passed in value {}".
format(original, value))
adjusted,original = y
if adjusted != original:
raise DateError("Invalid year {} passed in value {}".
format(original, value))
# ignore slash difference
if text:
self.text = text
@ -1609,26 +1643,30 @@ class Date(object):
"""
Calculate the numerical sort value associated with the date.
"""
year = max(self.dateval[Date._POS_YR], 1)
month = max(self.dateval[Date._POS_MON], 1)
day = max(self.dateval[Date._POS_DAY], 1)
year, month, day = self._zero_adjust_ymd(
self.dateval[Date._POS_YR],
self.dateval[Date._POS_MON],
self.dateval[Date._POS_DAY])
if year == month == 0 and day == 0:
self.sortval = 0
else:
func = Date._calendar_convert[self.calendar]
self.sortval = func(year, month, day)
def convert_calendar(self, calendar):
def convert_calendar(self, calendar, known_valid=True):
"""
Convert the date from the current calendar to the specified calendar.
"""
if calendar == self.calendar and self.newyear == Date.NEWYEAR_JAN1:
if (known_valid # if not known valid, round-trip convert anyway
and calendar == self.calendar
and self.newyear == Date.NEWYEAR_JAN1):
return
(year, month, day) = Date._calendar_change[calendar](self.sortval)
if self.is_compound():
ryear = max(self.dateval[Date._POS_RYR], 1)
rmonth = max(self.dateval[Date._POS_RMON], 1)
rday = max(self.dateval[Date._POS_RDAY], 1)
ryear, rmonth, rday = self._zero_adjust_ymd(
self.dateval[Date._POS_RYR],
self.dateval[Date._POS_RMON],
self.dateval[Date._POS_RDAY])
sdn = Date._calendar_convert[self.calendar](ryear, rmonth, rday)
(nyear, nmonth, nday) = Date._calendar_change[calendar](sdn)
self.dateval = (day, month, year, False,
@ -1692,6 +1730,12 @@ class Date(object):
"""
return (self.get_year(), self.get_month(), self.get_day())
def get_stop_ymd(self):
"""
Return (year, month, day) of the stop date, or all-zeros if it's not defined.
"""
return (self.get_stop_year(), self.get_stop_month(), self.get_stop_day())
def offset(self, value):
"""
Return (year, month, day) of this date +- value.

View File

@ -38,7 +38,7 @@ from ...config import config
from ...datehandler import get_date_formats, set_format
from ...datehandler import parser as _dp
from ...datehandler import displayer as _dd
from ...lib.date import Date
from ...lib.date import Date, DateError
date_tests = {}
@ -193,7 +193,7 @@ for calendar in (Date.CAL_JULIAN,
d.set(quality,modifier,calendar,(4,month,1789,False),"Text comment")
dates.append( d)
for calendar in (Date.CAL_HEBREW, Date.CAL_FRENCH):
for calendar in (Date.CAL_HEBREW, Date.CAL_HEBREW):
for month in range(1,14):
d = Date()
d.set(quality,modifier,calendar,(4,month,1789,False),"Text comment")
@ -422,6 +422,81 @@ class SwedishDateTest(BaseDateTest):
self.assertEqual(date.sortval,
date.to_calendar('gregorian').sortval)
class Test_set2(BaseDateTest):
"""
Test the Date.set2_... setters -- the ones to manipulate the 2nd date
of a compound date
"""
def setUp(self):
self.date = d = Date()
d.set(modifier=Date.MOD_RANGE,
#d m y sl--d m y sl
value=(1, 1, 2000, 0, 1, 1, 2010, 0))
def testStartStopSanity(self):
start,stop = self.date.get_start_stop_range()
self.assertEqual(start, (2000, 1, 1))
self.assertEqual(stop, (2010, 1, 1))
def test_set2_ymd_overrides_stop_date(self):
self.date.set2_yr_mon_day(2013, 2, 2)
start,stop = self.date.get_start_stop_range()
self.assertEqual(start, (2000, 1, 1))
self.assertEqual(stop, (2013, 2, 2))
def test_set_ymd_overrides_both_dates(self):
self.date.set_yr_mon_day(2013, 2, 2, remove_stop_date = True)
start,stop = self.date.get_start_stop_range()
self.assertEqual(start, stop)
self.assertEqual(stop, (2013, 2, 2))
def test_set_ymd_offset_updates_both_ends(self):
self.date.set_yr_mon_day_offset(+2, +2, +2)
start,stop = self.date.get_start_stop_range()
self.assertEqual(start, (2002, 3, 3))
self.assertEqual(stop, (2012, 3, 3))
def test_set2_ymd_offset_updates_stop_date(self):
self.date.set2_yr_mon_day_offset(+7, +5, +5)
start,stop = self.date.get_start_stop_range()
self.assertEqual(start, (2000, 1, 1))
self.assertEqual(stop, (2017, 6, 6))
def test_copy_offset_ymd_preserves_orig(self):
copied = self.date.copy_offset_ymd(year=-1)
self.testStartStopSanity()
start,stop = copied.get_start_stop_range()
self.assertEqual(start, (1999, 1, 1))
self.assertEqual(stop, (2009, 1, 1))
def test_copy_ymd_preserves_orig(self):
copied = self.date.copy_ymd(year=1000, month=10, day=10,
remove_stop_date=True)
self.testStartStopSanity()
start,stop = copied.get_start_stop_range()
self.assertEqual(start, (1000, 10, 10))
self.assertEqual(stop, (1000, 10, 10))
def _test_set2_function_raises_error_unless_compound(self, function):
for mod in (Date.MOD_NONE, Date.MOD_BEFORE, Date.MOD_AFTER,
Date.MOD_ABOUT,
Date.MOD_TEXTONLY):
self.date.set_modifier(mod)
try:
function(self.date)
self.assertTrue(False,
"Modifier: {}, dateval: {} - exception expected!".format(
mod, self.date.dateval))
except DateError:
pass
def test_set2_ymd_raises_error_unless_compound(self):
self._test_set2_function_raises_error_unless_compound(
lambda date: date.set2_yr_mon_day(2013, 2, 2))
def test_set2_ymd_offset_raises_error_unless_compound(self):
self._test_set2_function_raises_error_unless_compound(
lambda date: date.set2_yr_mon_day_offset(year=-1))
if __name__ == "__main__":
unittest.main()