Module:Date: Difference between revisions
update from sandbox: a date difference accepts an option to fill missing fields to handle partial dates
(update from sandbox: ranges of more time units) |
(update from sandbox: a date difference accepts an option to fill missing fields to handle partial dates) |
||
Line 897: | Line 897: | ||
end | end | ||
return date, options | return date, options | ||
end | |||
local function autofill(date1, date2) | |||
-- Fill any missing month or day in each date using the | |||
-- corresponding component from the other date, if present, | |||
-- or with 1 if both dates are missing the month or day. | |||
-- This gives a good result for calculating the difference | |||
-- between two partial dates when no range is wanted. | |||
-- Return filled date1, date2 (two full dates). | |||
local function filled(a, b) | |||
local fillmonth, fillday | |||
if not a.month then | |||
fillmonth = b.month or 1 | |||
end | |||
if not a.day then | |||
fillday = b.day or 1 | |||
end | |||
if fillmonth or fillday then -- need to create a new date | |||
a = Date(a, { month = fillmonth, day = fillday }) | |||
end | |||
return a | |||
end | |||
return filled(date1, date2), filled(date2, date1) | |||
end | end | ||
Line 1,160: | Line 1,183: | ||
options = {}, | options = {}, | ||
list = _date_list, | list = _date_list, | ||
subtract = function (self, rhs, options) | |||
return DateDiff(self, rhs, options) | |||
end, | |||
text = _date_text, | text = _date_text, | ||
} | } | ||
Line 1,538: | Line 1,564: | ||
} | } | ||
function DateDiff(date1, date2) -- for forward declaration above | function DateDiff(date1, date2, options) -- for forward declaration above | ||
-- Return a table with the difference between two dates (date1 - date2). | -- Return a table with the difference between two dates (date1 - date2). | ||
-- The difference is negative if date1 is older than date2. | -- The difference is negative if date1 is older than date2. | ||
Line 1,553: | Line 1,579: | ||
if not (is_date(date1) and is_date(date2) and date1.calendar == date2.calendar) then | if not (is_date(date1) and is_date(date2) and date1.calendar == date2.calendar) then | ||
return | return | ||
end | |||
local wantfill | |||
if type(options) == 'table' then | |||
wantfill = options.fill | |||
end | end | ||
local isnegative = false | local isnegative = false | ||
Line 1,571: | Line 1,601: | ||
-------------A===B------------------------- A=2001-04-01 B=2001-04-30 | -------------A===B------------------------- A=2001-04-01 B=2001-04-30 | ||
--------C=====================D------------ C=2001-01-01 D=2001-12-31 | --------C=====================D------------ C=2001-01-01 D=2001-12-31 | ||
local function zdiff(date1, date2) | if wantfill then | ||
date1, date2 = autofill(date1, date2) | |||
else | |||
local function zdiff(date1, date2) | |||
local diff = date1 - date2 | |||
if diff.isnegative then | |||
return date1 - date1 -- a valid diff in case we call its methods | |||
end | |||
return diff | |||
end | |||
local function getdate(date, which) | |||
return date.partial and date.partial[which] or date | |||
end | end | ||
local maxdiff = zdiff(getdate(date1, 'last'), getdate(date2, 'first')) | |||
local mindiff = zdiff(getdate(date1, 'first'), getdate(date2, 'last')) | |||
local years, months | |||
if maxdiff.years == mindiff.years then | |||
years = maxdiff.years | |||
if maxdiff.months == mindiff.months then | |||
months = maxdiff.months | |||
else | |||
months = { mindiff.months, maxdiff.months } | |||
end | |||
months = maxdiff.months | |||
else | else | ||
years = { mindiff.years, maxdiff.years } | |||
end | end | ||
return setmetatable({ | |||
date1 = date1, | |||
date2 = date2, | |||
partial = { | |||
years = years, | |||
months = months, | |||
maxdiff = maxdiff, | |||
mindiff = mindiff, | |||
}, | |||
isnegative = isnegative, | |||
iszero = iszero, | |||
age = _diff_age, | |||
duration = _diff_duration, | |||
}, diffmt) | |||
end | end | ||
end | end | ||
local y1, m1 = date1.year, date1.month | local y1, m1 = date1.year, date1.month |