Module:Date: Difference between revisions
date:list() now accepts a count; DateDiff methods age and duration; cleaner member names; remember if time entered with an am/pm option for default output
(rework date differences for more consistent years/months/days; differences include hours/minutes/seconds; can add 'date + diff'; tweaks) |
(date:list() now accepts a count; DateDiff methods age and duration; cleaner member names; remember if time entered with an am/pm option for default output) |
||
| Line 85: | Line 85: | ||
local a = floor((14 - date.month)/12) | local a = floor((14 - date.month)/12) | ||
local y = date.year + 4800 - a | local y = date.year + 4800 - a | ||
if date. | if date.calendar == 'Julian' then | ||
offset = floor(y/4) - 32083 | offset = floor(y/4) - 32083 | ||
else | else | ||
| Line 105: | Line 105: | ||
-- This handles the proleptic Julian and Gregorian calendars. | -- This handles the proleptic Julian and Gregorian calendars. | ||
-- Negative Julian dates are not defined but they work. | -- Negative Julian dates are not defined but they work. | ||
local calname = date. | local calname = date.calendar | ||
local low, high -- min/max limits for date ranges −9999-01-01 to 9999-12-31 | local low, high -- min/max limits for date ranges −9999-01-01 to 9999-12-31 | ||
if calname == 'Gregorian' then | if calname == 'Gregorian' then | ||
| Line 166: | Line 166: | ||
(-9999 <= y and y <= 9999 and | (-9999 <= y and y <= 9999 and | ||
1 <= m and m <= 12 and | 1 <= m and m <= 12 and | ||
1 <= d and d <= days_in_month(y, m, date. | 1 <= d and d <= days_in_month(y, m, date.calendar)) then | ||
return | return | ||
end | end | ||
| Line 199: | Line 199: | ||
-- If options1 is a string, return a table with its settings, or | -- If options1 is a string, return a table with its settings, or | ||
-- if it is a table, use its settings. | -- if it is a table, use its settings. | ||
-- Missing options are set from options2 or defaults. | -- Missing options are set from table options2 or defaults. | ||
-- If a default is used, a flag is set so caller knows the value was not intentionally set. | |||
-- Valid option settings are: | -- Valid option settings are: | ||
-- am: 'am', 'a.m.', 'AM', 'A.M.' | -- am: 'am', 'a.m.', 'AM', 'A.M.' | ||
| Line 209: | Line 210: | ||
-- BCMINUS displays a MINUS if year < 0 and the display format does not include %{era}. | -- BCMINUS displays a MINUS if year < 0 and the display format does not include %{era}. | ||
-- BCNEGATIVE is similar but displays a hyphen. | -- BCNEGATIVE is similar but displays a hyphen. | ||
local result = {} | local result = { bydefault = {} } | ||
if type(options1) == 'table' then | if type(options1) == 'table' then | ||
result = options1 | result.am = options1.am | ||
result.era = options1.era | |||
elseif type(options1) == 'string' then | elseif type(options1) == 'string' then | ||
-- Example: 'am:AM era:BC' or 'am=AM era=BC'. | -- Example: 'am:AM era:BC' or 'am=AM era=BC'. | ||
| Line 224: | Line 226: | ||
local defaults = { am = 'am', era = 'BC' } | local defaults = { am = 'am', era = 'BC' } | ||
for k, v in pairs(defaults) do | for k, v in pairs(defaults) do | ||
result[k] | if not result[k] then | ||
if options2[k] then | |||
result[k] = options2[k] | |||
else | |||
result[k] = v | |||
result.bydefault[k] = true | |||
end | |||
end | |||
end | end | ||
return result | return result | ||
| Line 287: | Line 296: | ||
M = { fmt = '%02d', fmt2 = '%d', field = 'minute' }, | M = { fmt = '%02d', fmt2 = '%d', field = 'minute' }, | ||
S = { fmt = '%02d', fmt2 = '%d', field = 'second' }, | S = { fmt = '%02d', fmt2 = '%d', field = 'second' }, | ||
j = { fmt = '%03d', fmt2 = '%d', field = ' | j = { fmt = '%03d', fmt2 = '%d', field = 'dayofyear' }, | ||
I = { fmt = '%02d', fmt2 = '%d', field = 'hour', special = 'hour12' }, | I = { fmt = '%02d', fmt2 = '%d', field = 'hour', special = 'hour12' }, | ||
p = { field = 'hour', special = 'am' }, | p = { field = 'hour', special = 'am' }, | ||
| Line 372: | Line 381: | ||
end | end | ||
if type(fmt) ~= 'string' then | if type(fmt) ~= 'string' then | ||
fmt = ' | fmt = 'dmy' | ||
if date.hastime then | if date.hastime then | ||
fmt = (date.second > 0 and 'hms ' or 'hm ') .. fmt | |||
end | end | ||
elseif fmt:find('%', 1, true) then | |||
return strftime(date, fmt, options) | return strftime(date, fmt, options) | ||
end | end | ||
local function hm_fmt() | |||
local plain = make_option_table(options, date.options).bydefault.am | |||
return plain and '%H:%M' or '%-I:%M %p' | |||
end | end | ||
local need_time = date.hastime | |||
local t = collection() | local t = collection() | ||
for item in fmt:gmatch('%S+') do | for item in fmt:gmatch('%S+') do | ||
local f | local f | ||
if item == 'hm' then | if item == 'hm' then | ||
f = | f = hm_fmt() | ||
need_time = false | |||
elseif item == 'hms' then | elseif item == 'hms' then | ||
f = '%H:%M:%S' | f = '%H:%M:%S' | ||
need_time = false | |||
elseif item == 'ymd' then | elseif item == 'ymd' then | ||
f = '%Y-%m-%d %{era}' | f = '%Y-%m-%d %{era}' | ||
| Line 403: | Line 413: | ||
t:add(f) | t:add(f) | ||
end | end | ||
fmt = t:join(' ') | |||
if need_time then | |||
fmt = hm_fmt() .. ' ' .. fmt | |||
end | |||
return strftime(date, fmt, options) | |||
end | end | ||
| Line 480: | Line 494: | ||
end | end | ||
local function | local function _date_list(date, spec) | ||
-- Return a possibly empty numbered table of dates meeting the specification. | -- Return a possibly empty numbered table of dates meeting the specification. | ||
-- The spec should be a string | -- Dates in the list are in ascending order (oldest date first). | ||
-- | -- The spec should be a string of form "<count> <day> <op>" | ||
-- where each item is optional and | |||
-- count = number of items wanted in list | |||
-- day = abbreviation or name such as Mon or Monday | |||
-- op = >, >=, <, <= (default is > meaning after date) | |||
-- If no count is given, the list is for the specified days in date's month. | |||
-- The default day is date's day. | |||
-- The spec can also be a positive or negative number: | |||
-- -5 is equivalent to '5 <' | |||
-- 5 is equivalent to '5' which is '5 >' | |||