438
edits
(support date difference codes 'dhms' and 'hms') |
m (3 revisions imported from wikipedia:Module:Date: see Topic:Vtixlm0q28eo6jtf) |
||
(11 intermediate revisions by 4 users not shown) | |||
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) | |||
-- Return date a filled, if necessary, with month and/or day from date b. | |||
-- The filled day is truncated to fit the number of days in the month. | |||
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 = math.min(fillday or a.day, days_in_month(a.year, fillmonth or a.month, a.calendar)) | |||
}) | |||
end | |||
return a | |||
end | |||
return filled(date1, date2), filled(date2, date1) | |||
end | end | ||
Line 1,160: | Line 1,188: | ||
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,329: | Line 1,360: | ||
local function choose(v) | local function choose(v) | ||
if type(v) == 'table' then | if type(v) == 'table' then | ||
if not wantrange then | if not wantrange or v[1] == v[2] then | ||
-- Example: Date('partial', 2005) - Date('partial', 2001) gives | -- Example: Date('partial', 2005) - Date('partial', 2001) gives | ||
-- diff.years = { 3, 4 } to show the range of possible results. | -- diff.years = { 3, 4 } to show the range of possible results. | ||
Line 1,350: | Line 1,381: | ||
if code == 'y' then | if code == 'y' then | ||
return choose(diff.partial.years) | return choose(diff.partial.years) | ||
end | |||
if code == 'm' or code == 'w' or code == 'd' then | |||
return choose({ diff.partial.mindiff:age(code), diff.partial.maxdiff:age(code) }) | |||
end | end | ||
return nil | return nil | ||
Line 1,367: | Line 1,401: | ||
end | end | ||
local H, M, S = diff.hours, diff.minutes, diff.seconds | local H, M, S = diff.hours, diff.minutes, diff.seconds | ||
if code == 'dh' or code == 'dhm' or code == 'dhms' or code == 'h' or code == 'hm' or code == 'hms' then | if code == 'dh' or code == 'dhm' or code == 'dhms' or code == 'h' or code == 'hm' or code == 'hms' or code == 'M' or code == 's' then | ||
local days = floor(diff.age_days + extra_days) | local days = floor(diff.age_days + extra_days) | ||
local inc_hour | local inc_hour | ||
Line 1,382: | Line 1,416: | ||
inc_hour = true | inc_hour = true | ||
end | end | ||
end | |||
elseif code == 'M' then | |||
if S >= 30 then | |||
M = M + 1 | |||
end | end | ||
else | else | ||
Line 1,408: | Line 1,446: | ||
elseif code == 'hm' then | elseif code == 'hm' then | ||
return hours, M | return hours, M | ||
elseif code == 'M' or code == 's' then | |||
M = hours * 60 + M | |||
if code == 'M' then | |||
return M | |||
end | |||
return M * 60 + S | |||
end | end | ||
return hours, M, S | return hours, M, S | ||
Line 1,535: | Line 1,579: | ||
} | } | ||
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,550: | Line 1,594: | ||
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,568: | Line 1,616: | ||
-------------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 | |||
return | 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 |