Module:Date: Difference between revisions
(rework date differences for more consistent years/months/days; differences include hours/minutes/seconds; can add 'date + diff'; tweaks) |
m (3 revisions imported from wikipedia:Module:Date: see Topic:Vtixlm0q28eo6jtf) |
||
| (19 intermediate revisions by 4 users not shown) | |||
| Line 69: | Line 69: | ||
local function hms(date) | local function hms(date) | ||
-- Return fraction of a day (0 <= fraction < 1) | -- Return fraction of a day from date's time, where (0 <= fraction < 1) | ||
-- if the values are valid, but could be anything if outside range. | |||
return (date.hour + (date.minute + date.second / 60) / 60) / 24 | return (date.hour + (date.minute + date.second / 60) / 60) / 24 | ||
end | end | ||
| Line 85: | Line 86: | ||
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 106: | ||
-- 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 149: | Line 150: | ||
date.year = 100*b + d - 4800 + floor(m/10) | date.year = 100*b + d - 4800 + floor(m/10) | ||
return true | return true | ||
end | |||
local function fix_numbers(numbers, y, m, d, H, M, S, partial, hastime, calendar) | |||
-- Put the result of normalizing the given values in table numbers. | |||
-- The result will have valid m, d values if y is valid; caller checks y. | |||
-- The logic of PHP mktime is followed where m or d can be zero to mean | |||
-- the previous unit, and -1 is the one before that, etc. | |||
-- Positive values carry forward. | |||
local date | |||
if not (1 <= m and m <= 12) then | |||
date = Date(y, 1, 1) | |||
if not date then return end | |||
date = date + ((m - 1) .. 'm') | |||
y, m = date.year, date.month | |||
end | |||
local days_hms | |||
if not partial then | |||
if hastime and H and M and S then | |||
if not (0 <= H and H <= 23 and | |||
0 <= M and M <= 59 and | |||
0 <= S and S <= 59) then | |||
days_hms = hms({ hour = H, minute = M, second = S }) | |||
end | |||
end | |||
if days_hms or not (1 <= d and d <= days_in_month(y, m, calendar)) then | |||
date = date or Date(y, m, 1) | |||
if not date then return end | |||
date = date + (d - 1 + (days_hms or 0)) | |||
y, m, d = date.year, date.month, date.day | |||
if days_hms then | |||
H, M, S = date.hour, date.minute, date.second | |||
end | |||
end | |||
end | |||
numbers.year = y | |||
numbers.month = m | |||
numbers.day = d | |||
if days_hms then | |||
-- Don't set H unless it was valid because a valid H will set hastime. | |||
numbers.hour = H | |||
numbers.minute = M | |||
numbers.second = S | |||
end | |||
end | end | ||
| Line 163: | Line 207: | ||
local M = numbers.minute or date.minute or 0 | local M = numbers.minute or date.minute or 0 | ||
local S = numbers.second or date.second or 0 | local S = numbers.second or date.second or 0 | ||
if | local need_fix | ||
(-9999 <= y and y <= 9999 and | if y and m and d then | ||
date.partial = nil | |||
if not (-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 | ||
if not date.want_fix then | |||
return | |||
end | |||
need_fix = true | |||
end | |||
elseif y and date.partial then | |||
if d or not (-9999 <= y and y <= 9999) then | |||
return | |||
end | |||
if m and not (1 <= m and m <= 12) then | |||
if not date.want_fix then | |||
return | |||
end | |||
need_fix = true | |||
end | |||
else | |||
return | return | ||
end | end | ||
if | if date.partial then | ||
-- | H = nil -- ignore any time | ||
M = nil | |||
S = nil | |||
else | else | ||
H = date. | if H then | ||
-- It is not possible to set M or S without also setting H. | |||
date.hastime = true | |||
else | |||
H = 0 | |||
end | |||
if not (0 <= H and H <= 23 and | |||
0 <= M and M <= 59 and | |||
0 <= S and S <= 59) then | |||
if date.want_fix then | |||
need_fix = true | |||
else | |||
return | |||
end | |||
end | |||
end | end | ||
if | date.want_fix = nil | ||
if need_fix then | |||
fix_numbers(numbers, y, m, d, H, M, S, date.partial, date.hastime, date.calendar) | |||
return | return set_date_from_numbers(date, numbers, options) | ||
end | end | ||
date.year = y -- -9999 to 9999 ('n BC' → year = 1 - n) | date.year = y -- -9999 to 9999 ('n BC' → year = 1 - n) | ||