Module:Date period

For templates, you might want to use {{Date period}} instead.

{{#invoke:Date period|_main|dateA|dateB}}

Automatically formats two given dates with a space and and en dash. Dates can be of any format supported by Module:Date.

If the month is the same, it is only shown once. If the month and day is the same, it will not show a second part at all. If the year is different, it will show the year unless disabled.

Date A Date B Output
2021-02-19 present February 19 – present
present 2021-02-25 present – February 25
2021-02-19 2021-02-25 February 19 – 25
2021-02-19 2021-03-25 February 19 – March 25
2020-02-19 2021-02-25 February 19, 2020 – February 25, 2021

The year can be forcefully shown with the force-year parameter (third parameter of p._main).

Date A Date B force-year Output
2021-02-19 2021-02-25 no February 19 – 25
2021-02-19 2021-02-25 yes February 19 – 25, 2021
2020-02-19 2021-02-25 no February 19 – February 25
2020-02-19 2021-02-25 yes February 19, 2020 – February 25, 2021

If one of the dates is invalid, the raw text will be displayed instead.

Date A Date B Output
2021-02-19 Sometime far in the future. February 19 – Sometime far in the future.
Long ago 2021-02-25 Long ago – February 25



local Date = require('Module:Date')._Date
local yesno = require('Module:Yesno')

local p = {}

local dateFormats = {
	["mdy"] = "%B %-d",
	["md"] = "%B %-d",
	["month"] = "%B %-d",
	["dmy"] = "%-d %B",
	["dm"] = "%-d %B",
	["day"] = "%-d %B"
}

function p.main(frame)
	return p._main(
		frame.args[1],
		frame.args[2],
		frame.args['force-year'],
		frame.args['format'] or "mdy"
	)
end

function p._main(_dateA, _dateB, _forceYear, _format)
	-- mdy by default
	local dateFormat = dateFormats[_format] or "%B %-d"
	
	if _dateA == nil and _dateB == nil then
		error('Date A or B not provided.')
	elseif _dateA == nil then
		return Date(_dateA):text(dateFormat)
	elseif _dateB == nil then
		return Date(_dateB):text(dateFormat)
	end
	
	local dateA = Date(_dateA)
	local dateB = Date(_dateB)
	
	if dateA == nil and dateB == nil then
		error("Either date A, date B, or both dates must be valid.")
	end
	
	local forceYear = yesno(_forceYear)
	
	-- Handle cases where one of the dates is not a valid date.
	if dateA == nil and dateB ~= nil then
		return _dateA .. ' – ' .. dateB:text(dateFormat) .. (forceYear and (', ' .. dateB.year) or '')
	elseif dateB == nil and dateA ~= nil then
		return dateA:text(dateFormat) .. (forceYear and (', ' .. dateA.year) or '') .. ' – ' .. _dateB
	end
	
	if dateA.year == dateB.year then
		if dateA.month == dateB.month and dateA.day == dateB.day then
			return dateA:text(dateFormat)
		elseif dateA.month == dateB.month then
			return dateA:text(dateFormat) .. ' – ' .. dateB.day .. (forceYear and (', ' .. dateA.year) or '')
		else
			return dateA:text(dateFormat) .. ' – ' .. dateB:text(dateFormat) .. (forceYear and (', ' .. dateA.year) or '')
		end
	else
		-- Hide year if forced
		if forceYear == false then
			return dateA:text(dateFormat) .. ' – ' .. dateB:text(dateFormat)
		else
			return dateA:text(dateFormat .. ', %-Y') .. ' – ' .. dateB:text(dateFormat .. ', %-Y')
		end
	end
	
end

return p