Модуль:Calendar

    Матеріал з Релігія в огні

    Документацію для цього модуля можна створити у Модуль:Calendar/документація

    --[[
      __  __           _       _         ____      _                _            
     |  \/  | ___   __| |_   _| | ___ _ / ___|__ _| | ___ _ __   __| | __ _ _ __ 
     | |\/| |/ _ \ / _` | | | | |/ _ (_) |   / _` | |/ _ \ '_ \ / _` |/ _` | '__|
     | |  | | (_) | (_| | |_| | |  __/_| |__| (_| | |  __/ | | | (_| | (_| | |   
     |_|  |_|\___/ \__,_|\__,_|_|\___(_)\____\__,_|_|\___|_| |_|\__,_|\__,_|_|   
                                                                                 
    This module is intended for date conversion between Gregorian and Julian calendars
    
    Please do not modify this code without applying the changes first at Module:Calendar/sandbox 
    and testing at Module:Calendar/sandbox/testcases 
    
    Maintainers:
    * Jarekt
    ]]
    require('strict')
    
    -- ==================================================
    -- === External functions ===========================
    -- ==================================================
    local p = {}
    
    -- ===========================================================================
    -- === Version of the function to be called from other LUA codes
    -- ===========================================================================
    
    -----------------------------------------------------------------------------
    --[[
    Convert calendar date to  "Julian day number" (jdn) 
    code based on  https://en.wikipedia.org/wiki/Julian_day#Converting_Julian_or_Gregorian_calendar_date_to_Julian_day_number
    explanation based on http://www.cs.utsa.edu/~cs1063/projects/Spring2011/Project1/project1.html
    
    Example usage:
      jdn = _date2jdn(2017-09-01, 1)
    
    Inputs:
      ISOdate:    date in YYYY-MM-DD format
      gregorian:  int - "1" for gregorian calendar and "0" for Julian (optional with "1" as default)
      
    Outputs:
      1: "Julian day number" as integer or number of days since Monday, January 1, 4713 BC
    
    ]]
    function p._date2jdn(ISOdate, gregorian)
      
    	local year, month, day = ISOdate:match( "(-?%d%d%d%d)-(%d%d)-(%d%d)" )
    	if not year then
    		return nil
    	elseif tonumber(year) < 0 then
    		-- If year is less than 0, add one to convert from  the common era system in which
    	    -- the year -1 (1 B.C.E) is followed by year 1 (1 C.E.) to a zero based date system
    		year = year + 1
    	end
    	local a, b, c, d, y, m
    	a = math.floor((14-month) / 12) -- will be 1 for January and February, and 0 for other months.
    	y = year + 4800 - a             -- years since year –4800
    	m = month + 12*a - 3            -- month number where 10 for January, 11 for February, 0 for March, 1 for April
    	c = math.floor((153*m + 2)/5)   -- number of days since March 1
    	if (gregorian or 1) >0 then	
    		b = math.floor(y/4) - math.floor(y/100) + math.floor(y/400) -- number of leap years since y==0 (year –4800)
    		d = 32045                   -- offset so the result will be 0 for January 1, 4713 BCE
    	else
    		b = math.floor(y/4)         -- number of leap years since y==0 (year –4800)
    		d = 32083                   -- offset so the result will be 0 for January 1, 4713 BCE
    	end
    	return day + c + 365*y + b - d
    end
    
    -----------------------------------------------------------------------------
    --[[
    Convert "Julian day number" (jdn) to a calendar date 
    code based on  https://en.wikipedia.org/wiki/Julian_day#Converting_Julian_or_Gregorian_calendar_date_to_Julian_day_number
    explanation based on http://www.cs.utsa.edu/~cs1063/projects/Spring2011/Project1/project1.html
    
    Example usage:
      jdn = _date2jdn(2017-09-01, 1)
    
    Inputs:
      jdn:       integer - Julian day number or number of days since Monday, January 1, 4713 BC
      gregorian: int - "1" for gregorian calendar and "0" for Julian (optional with "1" as default)
      
    Outputs:
      1: date in YYYY-MM-DD forma
    
    ]]
    -- Convert "Julian day number" (jdn) to a calendar date
    -- "gregorian" is a 1 for gregorian calendar and 0 for Julian
    -- based on https://en.wikipedia.org/wiki/Julian_day#Converting_Julian_or_Gregorian_calendar_date_to_Julian_day_number
    function p._jdn2date(jdn, gregorian)
      local f, e, g, h, year, month, day
    
    	f = jdn + 1401
    	if (gregorian or 1) >0 then
    		 f = f + math.floor((math.floor((4*jdn + 274277) / 146097) * 3) / 4) - 38
    	end
    	e = 4*f + 3
    	g = math.floor(math.fmod(e, 1461) / 4)
    	h = 5*g + 2
    	day   = math.floor(math.fmod (h,153) / 5) + 1
    	month = math.fmod (math.floor(h/153) + 2, 12) + 1
    	year  = math.floor(e/1461) - 4716 + math.floor((14 - month) / 12)
    	
    	-- If year is less than 1, subtract one to convert from a zero based date system to the
    	-- common era system in which the year -1 (1 B.C.E) is followed by year 1 (1 C.E.).
    	if year < 1 then
    			year = year - 1
    	end
    	
    	return string.format('%04i-%02i-%02i', year, month, day)
    end
    
    
    -- ===========================================================================
    -- === Versions of the function to be called from template namespace
    -- ===========================================================================
    --[[
    Gregorian2Julian
     
    Convert a date from Gregorian to Julian calendar
     
    Usage:
    {{#invoke:Calendar|Gregorian2Julian|YYYY-MM-DD}}
     
    Parameters:
        1: Gregorian date in YYYY-MM-DD format
    Output:
    	1: Julian date in YYYY-MM-DD format or error message "Error parsing input date: ....."
    ]]
    function p.Gregorian2Julian(frame)
    	local jdn = p._date2jdn(frame.args[1], 1)
    	if jdn then
    		return p._jdn2date(jdn, 0)
    	else
    		return "Error parsing input date: " .. frame.args[1]
    	end
    end
    
    -----------------------------------------------------------------------------
    --[[
    Julian2Gregorian
     
    Convert a date from Julian to Gregorian calendar
     
    Usage:
    {{#invoke:Calendar|Julian2Gregorian|YYYY-MM-DD}}
     
    Parameters:
        1: Julian date in YYYY-MM-DD format
    Output:
    	1: Gregorian date in YYYY-MM-DD format or error message "Error parsing input date: ....."
    ]]
    function p.Julian2Gregorian(frame)
    	local jdn = p._date2jdn(frame.args[1], 0)
    	if jdn then
    		return p._jdn2date(jdn, 1)
    	else
    		return "Error parsing input date: " .. frame.args[1]
    	end
    end
    
    -----------------------------------------------------------------------------
    --[[
    DayOfWeek
     
    Return day of week based on gregorian date. Returned value is in English. However 
    one can easily combine it with #Switch parser function [w:Help:Switch parser function]
    to translate to other languages
     
    Usage:
    {{#invoke:Calendar|DayOfWeek|date|lang=}}
     
    Parameters:
        1: date in YYYY-MM-DD format using Gregorian calendar
    Output:
    	1: day of the week in English or error message "Error parsing input date: ....."
    ]]
    
    function p.DayOfWeek(frame)
    	local jdn = p._date2jdn(frame.args[1], 1)
    	local day = math.fmod(jdn, 7) + 1
    	if day then
    		local LUT = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" }
    		return LUT[day]
    	else
    		return "Error parsing input date: " .. frame.args[1]
    	end
    end
    
    -----------------------------------------------------------------------------
    --[[
    date2jdn
     
    Convert calendar date to  "Julian day number" (jdn) 
     
    Usage:
    {{#invoke:Calendar|date2jdn|date}}
     
    Parameters:
        1: date in YYYY-MM-DD format (optional, if missing than today's date will be used)
    	2: calendar: "1" for Gregorian calendar and "0" for Julian (optional with "1" as default)
    Output:
        1: "Julian day number" as integer or number of days since Monday, January 1, 4713 BC
    ]]
    
    function p.date2jdn(frame)
    	return p._date2jdn(frame.args[1] or os.date('%F'), frame.args[2] or 1)
    end
    
    -----------------------------------------------------------------------------
    --[[
    jdn2date
     
    Convert "Julian day number" (jdn) to calendar date
     
    Usage:
    {{#invoke:Calendar|jdn2date|jdn}}
     
    Parameters:
        1: "Julian day number" as integer or number of days since Monday, January 1, 4713 BC
    	2: calendar: "1" for gregorian calendar and "0" for Julian (optional with "1" as default)
    Output:
        1: date in YYYY-MM-DD format 
    ]]
    function p.jdn2date(frame)
    	return p._jdn2date(frame.args[1], frame.args[2] or 1)
    end
    
    
    return p