if not date_time_values.month then
return generate_error(ERROR_MESSAGES.missing_month)
end  
local max_day = get_days_in_month(date_time_values.year, date_time_values.month)
if date_time_values.day < 1 or date_time_values.day > max_day then
return generate_error(string.format(ERROR_MESSAGES.invalid_day, date_time_values.month, max_day))
end
end  
-- Validate time components
if (date_time_values.minute or date_time_values.second) and not date_time_values.hour then
return generate_error(ERROR_MESSAGES.time_without_hour)
end  
if date_time_values.hour and (date_time_values.hour < 0 or date_time_values.hour > 23) then
return generate_error(ERROR_MESSAGES.invalid_hour)
end  
if date_time_values.minute and (date_time_values.minute < 0 or date_time_values.minute > 59) then
return generate_error(ERROR_MESSAGES.invalid_minute)
end  
if date_time_values.second and (date_time_values.second < 0 or date_time_values.second > 59) then
return generate_error(ERROR_MESSAGES.invalid_second)
end  
-- Timezone cannot be set without a specific date and hour
if args[7] and not (date_time_values.day and date_time_values.hour) then
return generate_error(ERROR_MESSAGES.timezone_incomplete_date)
elseif args[7] and not is_timezone_valid(args[7]) then
return generate_error(ERROR_MESSAGES.invalid_timezone)
end  
-- Validate that there aren't any duplicate parameters
if args.p and args.paren then
return generate_error(string.format(ERROR_MESSAGES.duplicate_parameters, "p", "paren"))
end  
-- Validate parameters that use "y" or "yes" for values
local boolean_params = {'df', 'p', 'paren', 'br'}
for _, param_name in ipairs(boolean_params) do
if args[param_name] and not (args[param_name] == "yes" or args[param_name] == "y") then
return generate_error(string.format(ERROR_MESSAGES.yes_value_parameter, param_name))
end
end  
return nil
end  
---
-- Public Functions --
---  
--- Validates date-time values from template arguments.
-- @param (table) The MediaWiki containing template arguments
-- @return nil|string Result of date-time validation
function p.validate_date_time
local get_args = require("Module:Arguments").getArgs
local args = get_args  
-- Sanitize inputs
args[7] = fix_timezone(args[7])  
return _validate_date_time(args)
end  
--- Generates a formatted date string with microformat markup.
-- @param (table) The MediaWiki containing template arguments
-- @return string A formatted date string, or an error message if validation fails
function p.generate_date
local get_args = require("Module:Arguments").getArgs
local args = get_args  
-- Sanitize inputs
args[7] = fix_timezone(args[7])  
local validation_error = _validate_date_time(args)
if validation_error then
return validation_error
end  
local classes = TEMPLATE_CLASSES[args.template or "start date"]
if not classes then
return generate_error(ERROR_MESSAGES.template, false)
end  
-- Process date-time values
local date_time_values = {
year = args[1],
month = pad_left_zeros(args[2]),
day = pad_left_zeros(args[3]),
hour = pad_left_zeros(args[4]),
minute = args[5] and pad_left_zeros(args[5]) or "00",
second = args[6] and pad_left_zeros(args[6]) or "00",
timezone = replace_minus_character(args[7], true) -- Restore U+2212 (Unicode minus)
}  
-- Generate individual components
local time_string = format_time_string(
date_time_values.hour,
date_time_values.minute,
date_time_values.second  
local date_string = format_date_string(
date_time_values.year,
date_time_values.month,
date_time_values.day,
args.df  
local timezone_string = format_timezone(date_time_values.timezone)  
local time_ago = ""
if TIME_AGO[args.template] then
time_ago = get_time_ago(
date_time_values,
args.br,
args.p or args.paren
end  
local h_calendar = generate_h_calendar(date_time_values, classes)  
-- Combine components
return time_string .. date_string .. timezone_string .. time_ago .. h_calendar
end  
return p