پودمان:Iranian calendar/library/تمرین

از ویکی‌پدیا، دانشنامهٔ آزاد
توضیحات پودمان[نمایش] [ویرایش] [تاریخچه] [پاکسازی]

استفاده[ویرایش]

{{#invoke:Iranian calendar/library|function_name}}

جدول قالب‌بندی[ویرایش]

کد توضیح دامنه نمونه
%a شمارهٔ فصل (ربع) از سال ق. ظ | ب. ظ ق. ظ
%b شمارهٔ فصل (ربع) از سال ۱ - ۴ ۱
%c Y/n/j ,H:i:s P : قالب مرکّب - ۱۳۹۰/۴/۴ ،۱۳:۰۸:۲۶ +۰۴:۳۰
%d شمارهٔ روز از ماه - ۲ رقمی ۰۱ - ۳۱ ۹
%f
%g
%h
%i
%j
%k
%l
%m
%n
%o
%p
%q
%r
%s
%t
%v
%w
%y
%z
%A
%D
%F
%G
%H
%J
%K
%L
%M
%N
%O
%Q
%S
%V
%W
-- This module is under development.

-- A library of Iranian calendar functions
-- Written by Alireza Eskandarpour Shoferi
-- Based on JalaliJSCalendar (by Ali Farhadi) and jdf (by Reza Gholampanahi)
--
-- Distributed under the terms of the CC BY-SA 4.0

-- load necessary modules
local data = require("Module:Iranian calendar/library/data")
local config = require("Module:Iranian calendar/library/config")
local formatNum = require("Module:Numeral converter").convert
local getArgs = require("Module:Arguments").getArgs

local p = {}

-- Used for calculating hour, seconds and minutes in Asia/Tehran timezone
local mw_en = mw.getLanguage("en")
local mw_fa = mw.getContentLanguage()

function p.getCurrentJalaliDateInTable()
	local date = os.date("!*t")

	date.hour = mw_en:formatDate('G', "+3 hours +30 minutes")
	date.sec = mw_en:formatDate('s', "+3 hours +30 minutes")
	date.min = mw_en:formatDate('i', "+3 hours +30 minutes")

	return p.toJalali(date)
end

function p.isKabise(frame)
	local args = getArgs(frame, {trim = true, removeBlanks = true})

	-- Giving the year argument in two ways
	args.year = formatNum("en", args[1] or args.year)

	return p._isKabise(args)
end

function p._isKabise(args)
	if args.year % 33 % 4 - 1 == math.floor(args.year % 33 * .05) then
		return 1
	else
		return 0
	end
end

-- givenDate argument should be a table of known keys (year, month, day, hour, min, and sec)
local function formatting(format, date, lang)
	local chars = {}
	for c in mw.ustring.gmatch(format,"%%%S") do
		-- If the special character is not exists already
		if type(chars[c]) == "nil" then
			chars[c] = ""
		end
	end

	local notSupportedChars = {}
	local isKabise = p.isKabise(date)
	-- To get the ISO day of the year 1 added (January 1 = 0).
	local dayOfYear = mw_en:formatDate("z", "+3 hours +30 minutes") + 1

	-- Following special characters and their expressions borrowed from http://jdf.scr.ir
	for k,_ in pairs(chars) do
		if k == "%a" then
			if tonumber(date.hour) < 12 then
				chars[k] = config.selectPhrase("abbrClock", 1)
			else
				chars[k] = config.selectPhrase("abbrClock", 2)
			end

		elseif k == "%b" then
			chars[k] = math.floor(date.month / 3.1 + 1)

		elseif k == "%c" then
			-- os.date("!%z") may not return what I need (not tested)
			chars[k] = date.year .. "/" .. date.month .. "/" .. date.day .. "،" .. date.hour .. ":" .. date.min .. ":" .. date.sec .. " " .. os.date("!%z")

		elseif k == "%d" then
			if date.day < 10 then
				chars[k] = "0" .. date.day
			else
				chars[k] = date.day
			end

		elseif k == "%f" then
			-- Key of tables in Lua starts from 1, so 1 added
			chars[k] = config.selectPhrase("seasons", math.floor((date.month / 3.1)) + 1)

		elseif k == "%g" then
			chars[k] = mw_en:formatDate("g", "+3 hours +30 minutes")

		elseif k == "%h" then
			chars[k] = mw_en:formatDate("h", "+3 hours +30 minutes")

		elseif k == "%i" then
			chars[k] = date.min

		elseif k == "%j" then
			chars[k] = mw_fa:formatDate("xij", "+3 hours +30 minutes")

		elseif k == "%k" then
			chars[k] = math.floor(100 - (dayOfYear / (p.isKabise(date) + 365) * 1000) / 10)

		elseif k == "%l" then
			-- Key of tables in Lua starts from 1, so 1 added
			chars[k] = config.selectPhrase("daysWeek", mw_en:formatDate("w", "+3 hours +30 minutes") + 1)

		elseif k == "%m" then
			if date.month > 9 then
				chars[k] = date.month
			else
				chars[k] = string.gsub(date.month,"([^0])","0%1")
			end

		elseif k == "%n" then
			chars[k] = mw_fa:formatDate("xin", "+3 hours +30 minutes")

		elseif k == "%o" then
			chars[k] = mw_fa:formatDate("xiY", "+3 hours +30 minutes")
			--[[local jdw
			if date.wday == 6 then
				jdw = 0
			else
				jdw = date.wday + 1
			end
			local dny = 364 + p.isKabise(date) - dayOfYear
			if (jdw > (dayOfYear + 3) and dayOfYear < 3) then
				chars[k] = date.year - 1
			else 
				if (3-dny) > jdw and dny < 3 then
					chars[k] = date.year + 1
				else
					chars[k] = date.year
				end
			end]]--

	elseif k == "%p" then
		chars[k] = config.selectPhrase("astrologicalSign", date.month)

	elseif k == "%q" then
		chars[k] = config.selectPhrase("astrologicalSign", (date.year % 12))

	elseif k == "%r" then
		-- inja

	elseif k == "%s" then
		chars[k] = date.sec

	elseif k == "%t" then
		if date.month ~= 12 then
			chars[k] = math.floor(31 - date.month / 6.5)
		else
			chars[k] = p.isKabise(date.year) + 29
		end

	elseif k == "%v" then
		local sl = 2
		local num = string.sub(date.year, 3)
		local xy3 = string.sub(num, 2 - sl, 1)
		local h3 = ""
		local h34 = ""
		local h4 = ""
		local p34
		if xy3 == 1 then
			p34 = ""
			h34 = config.selectPhrase("k34", string.sub(num, 2 - sl, 2) - 10)
		else
			local xy4 = string.sub(num, 3 - sl, 1)
			if xy3 == 0 or xy4 == 0 then
				p34 = ""
			else
				p34 = config.selectPhrase("andWord")
			end
			h3 = config.selectPhrase("k3", xy3)
			h4 = config.selectPhrase("k4", xy4)
		end
		if num > 99 then
			local numbs = {"12", "13", "14", "19", "20"}
			for i = 1, 5 do
				num = string.gsub(string.sub(date.year, 1, 2), numbs[i], config.selectPhrase("thousands", i))
				if string.sub(date.year, 3) == "00" then
					num = num .. h3 .. p34 .. h34 .. h4
				else
					num = num .. config.selectPhrase("andWord") .. h3 .. p34 .. h34 .. h4
				end
			end
			chars[k] = num
		else
			chars[k] = ""
		end

	elseif k == "%w" then
		if date.wday == 6 then
			chars[k] = 0
		else 
			chars[k] = date.wday + 1
		end

	elseif k == "%y" then
		chars[k] = string.sub(date.year, 3)

	elseif k == "%z" then
		chars[k] = dayOfYear

	elseif k == "%A" then
		if tonumber(date.hour) < 12 then
			chars[k] = config.selectPhrase("clock", 1)
		else
			chars[k] = config.selectPhrase("clock", 2)
		end

	elseif k == "%D" then
		chars[k] = config.selectPhrase("abbrDaysWeekOneCharacter", (tonumber(date.wday)))

	elseif k == "%F" then
		chars[k] = config.selectPhrase("months", tonumber(date.month))

	elseif k == "%G" then
		chars[k] = date.hour

	elseif k == "%H" then
		chars[k] = mw_en:formatDate("H", "+3 hours +30 minutes")

	elseif k == "%J" then
		chars[k] = config.selectPhrase("daysMonthNumberWord", tonumber(date.day))

	elseif k == "%K" then
		chars[k] = math.floor((dayOfYear/(p.isKabise(date) + 365) * 1000) / 10)

	elseif k == "%L" then
		chars[k] = p.isKabise(date)

	elseif k == "%M" then
		chars[k] = config.selectPhrase("abbrMonths", tonumber(date.month))

	elseif k == "%N" then
		chars[k] = tonumber(date.wday)

	elseif k == "%O" then
		chars[k] = os.date("!%z")

	elseif k == "%Q" then
		chars[k] = isKabise + 364 - dayOfYear

	elseif k == "%S" then
		chars[k] = config.selectPhrase("suffix")

	elseif k == "%V" then
		local sl = 4
		local num = date.year
		local xy3 = string.sub(num, 2 - sl, 1)
		local h3 = ""
		local h34 = ""
		local h4 = ""
		local p34
		if xy3 == 1 then
			p34 = ""
			h34 = config.selectPhrase("k34", string.sub(num, 2 - sl, 2) - 10)
		else
			local xy4 = string.sub(num, 3 - sl, 1)
			if xy3 == 0 or xy4 == 0 then
				p34 = ""
			else
				p34 = config.selectPhrase("andWord")
			end
			h3 = config.selectPhrase("k3", xy3)
			h4 = config.selectPhrase("k4", xy4)
		end
		if num > 99 then
			local numbs = {"12", "13", "14", "19", "20"}
			for i = 1, 5 do
				num = string.gsub(string.sub(date.year, 1, 2), numbs[i], config.selectPhrase("thousands", i))
				if string.sub(date.year, 3) == "00" then
					num = num .. h3 .. p34 .. h34 .. h4
				else
					num = num .. config.selectPhrase("andWord") .. h3 .. p34 .. h34 .. h4
				end
			end
			chars[k] = num
		else
			chars[k] = ""
		end

	elseif k == "%W" then
		local avs
		if date.wday == 6 then
			avs = 0
		else
			avs = date.wday + 1
		end
		avs = avs - dayOfYear % 7
		if avs < 0 then 
			avs = avs + 7
		end
		local num = math.floor((dayOfYear + avs) / 7)
		if avs < 4 then
			num = num + 1
		elseif num < 1 then
			if avs == 4 then
				num = 53
			elseif date.year % 33 % 4 - 2 == math.floor(date.year % 33 * .05) then
				if avs == 5 then
					num = 53
				end
			elseif date.year % 33 % 4 - 2 ~= math.floor(date.year % 33 * .05) then
				if avs == 4 then
					num = 52
				end
			else
				num = 52
			end
		end
		local aks = avs + isKabise
		if aks == 7 then
			aks = 0
		end
		if(isKabise + 363 - dayOfYear) < aks and aks < 3 then
			chars[k] = "01"
		else
			if (num < 10) then
				chars[k] = "0" .. num
			else
				chars[k] = num
			end
		end
		-- The given special character is not supported
	else
		table.insert(notSupportedChars, k)
	end
end
if #notSupportedChars > 0 then
	error(string.format(config.selectPhrase("errors", "notSupportedCharacters", lang), table.concat(notSupportedChars, ", ")))
else
	for k,v in pairs(chars) do
		format = mw.ustring.gsub(format, "%"..k, v)
	end
	return format
end
end

function p.toGregorian(frame)
	local args = getArgs(frame, {trim = true, removeBlanks = true})

	args.year = tonumber(formatNum("en", args[1] or args.year)) - 979
	args.month = tonumber(formatNum("en", args[2] or args.month)) - 1
	args.day = tonumber(formatNum("en", args[3] or args.day)) - 1

	return p._toGregorian(args)
end

function p._toGregorian(args)
	local jalDayNum = 365 * args.year + math.floor(args.year / 33) * 8 + math.floor((args.year % 33 + 3) / 4)
	local i = 0
	while i < args.month do
		i = i + 1
		jalDayNum = jalDayNum + data.daysMonth.jalali[i]
	end

	jalDayNum = jalDayNum + args.day

	local greDayNum = jalDayNum + 79

	-- 146097 = 365*400 + 400/4 - 400/100 + 400/400
	local greYear = 1600 + 400 * math.floor(greDayNum / 146097)
	greDayNum = greDayNum % 146097

	local leap = true
	-- 36525 = 365*100 + 100/4
	if (greDayNum >= 36525) then
		greDayNum = greDayNum - 1
		-- 36524 = 365*100 + 100/4 - 100/100
		greYear = greYear + 100 * math.floor(greDayNum / 36524)
		greDayNum = greDayNum % 36524

		if (greDayNum >= 365) then
			greDayNum = greDayNum + 1
		else
			leap = false
		end
	end

	-- 1461 = 365*4 + 4/4
	greYear = greYear + 4 * math.floor(greDayNum / 1461)
	greDayNum = greDayNum % 1461

	if (greDayNum >= 366) then
		leap = false

		greDayNum = greDayNum - 1
		greYear = greYear + math.floor(greDayNum / 365)
		greDayNum = greDayNum % 365
	end

	i = 0
	while greDayNum >= data.daysMonth.gregorian[i+1] + ((i == 1 and leap) and 1 or 0) do
		greDayNum = greDayNum - data.daysMonth.gregorian[i+1] + ((i == 1 and leap) and 1 or 0)
		i = i + 1
	end

	return {year = greYear, month = i+1, day = greDayNum+1}
end

function p.checkDate(frame)
	local args = getArgs(frame, {trim = true, removeBlanks = true})

	args.year = tonumber(formatNum("en", args[1]))
	args.month = tonumber(formatNum("en", args[2]))
	args.day = tonumber(formatNum("en", args[3]))

	return p._checkDate(args)
end

function p._checkDate(args)
	return not(args.year < 0 or args.year > 32767 or args.month < 1 or args.month > 12 or args.day < 1 or args.day >
		((data.daysMonth.jalali[args.month] or 0) + ((args.month == 12 and not(((args.year - 979) % 33 % 4) and 1 or 0)) and 1 or 0)))
end

function p.toJalali(frame)
	local args = getArgs(frame, {trim = true, removeBlanks = true})

	args.year = tonumber(formatNum("en", args[1] or args.year)) - 1600
	args.month = tonumber(formatNum("en", args[2] or args.month)) - 1
	args.day = tonumber(formatNum("en", args[3] or args.day)) - 1

	return p._toJalali(args)
end

function p._toJalali(args)
	local greDayNum = 365 * args.year + math.floor((args.year + 3) / 4) - math.floor((args.year + 99) / 100) + math.floor((args.year + 399) / 400)

	local i = 0
	while i <= args.month do
		i = i + 1
		greDayNum = greDayNum + data.daysMonth.gregorian[i]
	end
	if (args.month > 1 and ((args.year % 4 == 0 and args.year % 100 ~= 0) or (args.year % 400 == 0))) then
		-- leap and after Feb
		greDayNum = greDayNum + 1
	end
	greDayNum = greDayNum + args.day

	local jalDayNum = greDayNum - 79

	local j_np = math.floor(jalDayNum / 12053)
	jalDayNum = jalDayNum % 12053

	local jalaliYear = 979 + 33 * j_np + 4 * math.floor(jalDayNum / 1461)

	jalDayNum = jalDayNum % 1461

	if (jalDayNum >= 366) then
		jalaliYear = jalaliYear + math.floor((jalDayNum - 1) / 365)
		jalDayNum = (jalDayNum - 1) % 365
	end

	i = 0
	while i <= 11 and jalDayNum > data.daysMonth.jalali[i+1] do
		i = i + 1
		jalDayNum = jalDayNum - data.daysMonth.jalali[i]
	end

	args.year = jalaliYear
	args.month = i
	args.day = jalDayNum + 1

	return args
end

function p.getCurrentJalaliYear(frame)
	local args = getArgs(frame, {trim = true, removeBlanks = true})

	args.lang = args.lang or config.defaultLang

	return p._getCurrentJalaliYear(args)
end

function p._getCurrentJalaliYear(args)
	return formatNum(args.lang, p.getCurrentJalaliDateInTable().year)
end

function p.getCurrentJalaliMonth(frame)
	local args = getArgs(frame, {trim = true, removeBlanks = true})

	args.lang = args.lang or config.defaultLang

	return p._getCurrentJalaliMonth(args)
end

function p._getCurrentJalaliMonth(args)
	return formatNum(args.lang, p.getCurrentJalaliDateInTable().month)
end

function p.getFormattedCurrentJalaliDate(frame)
	local args = getArgs(frame, {trim = true, removeBlanks = true})

	args.lang = args.lang or config.defaultLang
	args.format = args.format or config.defaultFormat

	return p._getFormattedCurrentJalaliDate(args)
end

function p._getFormattedCurrentJalaliDate(args)
	return formatNum(args.lang, formatting(args.format, p.getCurrentJalaliDateInTable(), args.lang))
end

function p.getCurrentJalaliDay(frame)
	local args = getArgs(frame, {trim = true, removeBlanks = true})

	args.lang = args.lang or config.defaultLang

	return p._getCurrentJalaliDay(args)
end

function p._getCurrentJalaliDay(args)
	return formatNum(args.lang, p.getCurrentJalaliDateInTable().day)
end

return p