Module:Date: Difference between revisions

    (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
    local diff = date1 - date2
    date1, date2 = autofill(date1, date2)
    if diff.isnegative then
    else
    return date1 - date1  -- a valid diff in case we call its methods
    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
    return diff
    local maxdiff = zdiff(getdate(date1, 'last'), getdate(date2, 'first'))
    end
    local mindiff = zdiff(getdate(date1, 'first'), getdate(date2, 'last'))
    local function getdate(date, which)
    local years, months
    return date.partial and date.partial[which] or date
    if maxdiff.years == mindiff.years then
    end
    years = maxdiff.years
    local maxdiff = zdiff(getdate(date1, 'last'), getdate(date2, 'first'))
    if maxdiff.months == mindiff.months then
    local mindiff = zdiff(getdate(date1, 'first'), getdate(date2, 'last'))
    months = maxdiff.months
    local years, months
    else
    if maxdiff.years == mindiff.years then
    months = { mindiff.months, maxdiff.months }
    years = maxdiff.years
    end
    if maxdiff.months == mindiff.months then
    months = maxdiff.months
    else
    else
    months = { mindiff.months, maxdiff.months }
    years = { mindiff.years, maxdiff.years }
    end
    end
    else
    return setmetatable({
    years = { mindiff.years, maxdiff.years }
    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
    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
    local y1, m1 = date1.year, date1.month
    local y1, m1 = date1.year, date1.month