local a={}local L={"\074\097\110\117\097\114\121";"\070\101\098\114\117\097\114\121";"\077\097\114\099\104","\065\112\114\105\108","\077\097\121","\074\117\110\101";"\074\117\108\121";"\065\117\103\117\115\116";"\083\101\112\116\101\109\098\101\114","\079\099\116\111\098\101\114","\078\111\118\101\109\098\101\114","\068\101\099\101\109\098\101\114"}local I={"\074\097\110";"\070\101\098";"\077\097\114","\065\112\114";"\077\097\121","\074\117\110";"\074\117\108","\065\117\103","\083\101\112";"\079\099\116";"\078\111\118";"\068\101\099"}local R={31;28;31,30,31;30;31,31;30;31,30,31}local X={"\083\117\110\100\097\121","\077\111\110\100\097\121";"\084\117\101\115\100\097\121","\087\101\100\110\101\115\100\097\121";"\084\104\117\114\115\100\097\121","\070\114\105\100\097\121";"\083\097\116\117\114\100\097\121"}local P={"\083\117\110";"\077\111\110";"\084\117\101\115";"\087\101\100\115","\084\104\117\114\115";"\070\114\105";"\083\097\116"}local function A(a)local L={}for a,I in pairs(R)do L[a]=I end if a%4==0 and(a%100~=0 or a%400==0)then L[2]=29 else L[2]=28 end return L end function a.GetSecond(a)return math.floor(a%60)end function a.GetMinute(a)return math.floor((a/60)%60)end function a.GetHour(a)return math.floor((a/3600)%24)end function a.GetDay(a)local L=math.ceil((((a/60)/60)/24)%365.25)return L end function a.GetYear(a)local L=math.floor((((a/60)/60)/24)/365.25+1970)return L end function a.GetYearShort(L)local I=a.GetYear(L)return I%100 end function a.GetYearShortFormatted(L)local I=a.GetYearShort(L)if I<10 then I="\048"..I end return I end function a.GetMonth(L)local I=a.GetYear(L)local R=a.GetDay(L)local X local P=A(I)for a=1,#P,1 do if R>P[a]then R=R-P[a]else return a end end end function a.GetFormattedMonth(L)local I=a.GetMonth(L)if I<10 then I="\048"..I end return I end function a.GetDayOfTheMonth(L)local I=a.GetYear(L)local R=a.GetDay(L)local X local P=A(I)for a=1,#P,1 do if R>P[a]then R=R-P[a]else return R end end end function a.GetFormattedDayOfTheMonth(L)local I=a.GetDayOfTheMonth(L)if I<10 then I="\048"..I end return I end function a.GetMonthName(I)return L[a.GetMonth(I)]end function a.GetMonthNameShort(L)return I[a.GetMonth(L)]end function a.GetJulianDate(L)local I=a.GetMonth(L)local R=a.GetYear(L)local X=a.GetDay(L)local P=(14-I)/12 local A=(R+4800)-P local i=(I+12*P)-3 local q=(((((X+(153*i+2)/5)+365*A)+A/4)-A/100)+A/400)-32045 return q end function a.GetDayOfTheWeek(L)local I=a.GetJulianDate(L)return math.floor(I)%7 end function a.GetDayOfTheWeekName(L)local I=a.GetDayOfTheWeek(L)local R=X[I]return R end function a.GetDayOfTheWeekNameShort(L)local I=a.GetDayOfTheWeek(L)local R=P[I]return R end function a.GetOrdinalOfNumber(a)local L=a%10 local I=a%100 if I>=10 and I<=20 then return"\116\104"end if L==1 then return"\115\116"elseif L==2 then return"\110\100"elseif L==3 then return"\114\100"else return"\116\104"end end function a.GetDayOfTheMonthOrdinal(L)local I=a.GetDayOfTheMonth(L)return a.GetOrdinalOfNumber(I)end function a.GetFormattedSecond(L)local I=a.GetSecond(L)if I<10 then I="\048"..I end return I end function a.GetFormattedMinute(L)local I=a.GetMinute(L)if I<10 then I="\048"..I end return I end function a.GetRegularHour(L)local I=a.GetHour(L)if I>12 then I=I-12 end return I end function a.GetHourFormatted(L)local I=a.GetHour(L)if I<10 then I="\048"..I end return I end function a.GetRegularHourFormatted(L)local I=a.GetRegularHour(L)if I<10 then I="\048"..I end return I end function a.GetamOrpm(L)local I=a.GetHour(L)if I>12 then return"\112\109"else return"\097\109"end end function a.GetAMorPM(L)local I=a.GetHour(L)if I>12 then return"\080\077"else return"\065\077"end end function a.GetMilitaryHour(L)local I=a.GetHour(L)if I<10 then I="\048"..I end end function a.LeapYear(L)local I=a.GetYear(L)if I%4==0 and(I%100~=0 or I%400==0)then return 1 else return 0 end end function a.GetDaysInMonth(L)local I=a.GetMonth(L)local R=a.GetYear(L)return(A(R))[I]end local i={d=a.GetFormattedDayOfTheMonth;D=a.GetDayOfTheWeekNameShort;j=a.GetDayOfTheMonth,l=a.GetDayOfTheWeekName,N=a.GetDayOfTheWeek,S=a.GetDayOfTheMonthOrdinal,W=a.GetDayOfTheWeek,Z=a.GetDay,F=a.GetMonthName,m=a.GetFormattedMonth,M=a.GetMonthNameShort,n=a.GetMonth;t=a.GetDaysInMonth,L=a.LeapYear;o=a.GetYear;Y=a.GetYear,y=a.GetYearShortFormatted;a=a.GetamOrpm,A=a.GetAMorPM,g=a.GetRegularHour;G=a.GetHour;h=a.GetRegularHourFormatted,H=a.GetHourFormatted;i=a.GetFormattedMinute,s=a.GetFormattedSecond,X=a.GetJulianDate,U=time}local q="\091"do for a,L in pairs(i)do q=q..a end q=q.."\093"end function a.GetFormattedTime(a,L)L=L or tick()local I=a local R={}for a in string.gmatch(a,q)do R[#R+1]=a end for a,L in pairs(R)do I=I:gsub(L,L:rep(3))end for a,R in pairs(R)do local X=i[R](L)I=I:gsub(R:rep(3),X)end return I end return a
--- Library handles time based parsing / operations. Untested. Based off of PHP.
-- @module Time

local lib = {}

local MONTH_NAMES        = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}
local MONTH_NAMES_SHORT  = {"Jan",     "Feb",      "Mar",   "Apr",   "May", "Jun",  "Jul",  "Aug",    "Sep",       "Oct",     "Nov",      "Dec"}
local DAYS_IN_MONTH      = { 31,        28,         31,      30,      31,    30,     31,     31,       30,          31,       30,         31}
local DAYS_OF_WEEK       = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
local DAYS_OF_WEEK_SHORT = {"Sun",    "Mon",    "Tues",    "Weds",      "Thurs",    "Fri",    "Sat"}

--- Returns a Days in months table for the given year
local function GetDaysMonth(Year)
	local Copy = {}
	for Index, Value in pairs(DAYS_IN_MONTH) do
		Copy[Index] = Value
	end

	if Year % 4 == 0 and (Year % 100 ~= 0 or Year % 400 == 0) then
		Copy[2] = 29
	else
		Copy[2] = 28
	end

	return Copy
end

function lib.GetSecond(CurrentTime)
	return math.floor(CurrentTime % 60)
end

function lib.GetMinute(CurrentTime)
	return math.floor(CurrentTime/60 % 60)
end

function lib.GetHour(CurrentTime)
	return math.floor(CurrentTime/3600 % 24)
end

function lib.GetDay(CurrentTime)
	local CurrentDay = math.ceil(CurrentTime/60/60/24 % 365.25)
	return CurrentDay
end

function lib.GetYear(CurrentTime) 
	local CurrentYear = math.floor(CurrentTime/60/60/24/365.25 + 1970)

	return CurrentYear
end

function lib.GetYearShort(CurrentTime)
	local Year = lib.GetYear(CurrentTime)
	return Year % 100
end

function lib.GetYearShortFormatted(CurrentTime) 
	local ShortYear = lib.GetYearShort(CurrentTime)
	if ShortYear < 10 then
		ShortYear = "0" .. ShortYear
	end
	return ShortYear
end

function lib.GetMonth(CurrentTime)
	local Year = lib.GetYear(CurrentTime)
	local Day = lib.GetDay(CurrentTime)
	local Month

	local DaysInMonth = GetDaysMonth(Year)

	for Index=1, #DaysInMonth do
		if Day > DaysInMonth[Index] then
			Day = Day - DaysInMonth[Index]
		else
			return Index
		end
	end
end

function lib.GetFormattedMonth(CurrentTime)
	local Month = lib.GetMonth(CurrentTime)
	if Month < 10 then
		Month = "0"..Month
	end

	return Month
end

function lib.GetDayOfTheMonth(CurrentTime)
	local Year = lib.GetYear(CurrentTime)
	local Day = lib.GetDay(CurrentTime)
	local DayOfTheMonth

	local DaysInMonth = GetDaysMonth(Year)

	for Index=1, #DaysInMonth do
		if Day > DaysInMonth[Index] then
			Day = Day - DaysInMonth[Index]
		else
			return Day
		end
	end
end

function lib.GetFormattedDayOfTheMonth(CurrentTime)
	local DayOfTheMonth = lib.GetDayOfTheMonth(CurrentTime)

	if DayOfTheMonth < 10 then
		DayOfTheMonth = "0"..DayOfTheMonth
	end

	return DayOfTheMonth
end

function lib.GetMonthName(CurrentTime)
	return MONTH_NAMES[lib.GetMonth(CurrentTime)]
end

function lib.GetMonthNameShort(CurrentTime)
	return MONTH_NAMES_SHORT[lib.GetMonth(CurrentTime)]
end

function lib.GetJulianDate(CurrentTime)
	local Month = lib.GetMonth(CurrentTime)
	local Year = lib.GetYear(CurrentTime)
	local Day = lib.GetDay(CurrentTime)

	local A = (14-Month) / 12
	local Y = Year + 4800 - A
	local M = Month + 12 * A - 3

	local JulianDay = Day + ((153 * M + 2) / 5) + 365 * Y + (Y/4) - (Y/100) + (Y/400) - 32045

	--[[local JulianDay = (Day 
	+ ((153 * (Month + 12 * ((14 - Month) / 12 ) - 3) + 2) / 5)
	+ (365 * (Year + 4800 - ((14 - Month) / 12)))
	+ ((Year + 4800 - ((14 - Month) / 12)) / 4)
	+ ((Year + 4800 - ((14 - Month) / 12)) / 100)
	+ ((Year + 4800 - ((14 - Month) / 12)) / 400)
	- 32045)--]]

	return JulianDay
end

function lib.GetDayOfTheWeek(CurrentTime)

	local JulianTime = lib.GetJulianDate(CurrentTime)

	return math.floor(JulianTime) % 7
end

function lib.GetDayOfTheWeekName(CurrentTime)
	local DayOfTheWeek = lib.GetDayOfTheWeek(CurrentTime)
	local Name = DAYS_OF_WEEK[DayOfTheWeek]

	return Name
end

function lib.GetDayOfTheWeekNameShort(CurrentTime) 
	local DayOfTheWeek = lib.GetDayOfTheWeek(CurrentTime)
	local Name = DAYS_OF_WEEK_SHORT[DayOfTheWeek] 

	return Name
end

---
-- @return st, nd (Like 1st, 2nd)
function lib.GetOrdinalOfNumber(Number) 
	local TenRemainder = Number % 10
	local HundredRemainder = Number % 100

	if HundredRemainder >= 10 and HundredRemainder <= 20 then
		return "th"
	end

	if TenRemainder == 1 then
		return "st"
	elseif TenRemainder == 2 then
		return "nd"
	elseif TenRemainder == 3 then
		return "rd"
	else
		return "th"
	end
end

function lib.GetDayOfTheMonthOrdinal(CurrentTime)
	local DayOfTheMonth = lib.GetDayOfTheMonth(CurrentTime)

	return lib.GetOrdinalOfNumber(DayOfTheMonth)
end

function lib.GetFormattedSecond(CurrentTime)
	local CurrentSecond = lib.GetSecond(CurrentTime)
	if CurrentSecond < 10 then
		CurrentSecond = "0"..CurrentSecond
	end
	return CurrentSecond
end

function lib.GetFormattedMinute(CurrentTime)
	local CurrentMinute = lib.GetMinute(CurrentTime)

	if CurrentMinute < 10 then
		CurrentMinute = "0".. CurrentMinute
	end

	return CurrentMinute
end

function lib.GetRegularHour(CurrentTime)
	local CurrentHour = lib.GetHour(CurrentTime)

	if CurrentHour > 12 then
		CurrentHour = CurrentHour - 12
	end

	return CurrentHour
end

function lib.GetHourFormatted(CurrentTime)
	local CurrentHour = lib.GetHour(CurrentTime)

	if CurrentHour < 10 then
		CurrentHour = "0"..CurrentHour
	end

	return CurrentHour
end

function lib.GetRegularHourFormatted(CurrentTime)
	local CurrentHour = lib.GetRegularHour(CurrentTime)

	if CurrentHour < 10 then
		CurrentHour = "0"..CurrentHour
	end

	return CurrentHour
end

function lib.GetamOrpm(CurrentTime)
	local CurrentHour = lib.GetHour(CurrentTime)

	if CurrentHour > 12 then
		return "pm"
	else
		return "am"
	end
end

function lib.GetAMorPM(CurrentTime)
	local CurrentHour = lib.GetHour(CurrentTime)

	if CurrentHour > 12 then
		return "PM"
	else
		return "AM"
	end
end

function lib.GetMilitaryHour(CurrentTime)
	local CurrentHour = lib.GetHour(CurrentTime)

	if CurrentHour < 10 then
		CurrentHour = "0"..CurrentHour
	end
end

function lib.LeapYear(CurrentTime)
	local Year = lib.GetYear(CurrentTime)

	if Year % 4 == 0 and (Year % 100 ~= 0 or Year % 400 == 0) then
		return 1
	else
		return 0
	end
end

function lib.GetDaysInMonth(CurrentTime)
	local Month = lib.GetMonth(CurrentTime)
	local Year = lib.GetYear(CurrentTime)

	return GetDaysMonth(Year)[Month]
end

local ISO_FORMAT_STRINGS = {
	d = lib.GetFormattedDayOfTheMonth;
	D = lib.GetDayOfTheWeekNameShort;
	j = lib.GetDayOfTheMonth;
	l = lib.GetDayOfTheWeekName;
	N = lib.GetDayOfTheWeek;
	S = lib.GetDayOfTheMonthOrdinal;
	W = lib.GetDayOfTheWeek;
	Z = lib.GetDay;

	-- W 

	F = lib.GetMonthName;
	m = lib.GetFormattedMonth;
	M = lib.GetMonthNameShort;
	n = lib.GetMonth;
	t = lib.GetDaysInMonth;

	L = lib.LeapYear;
	o = lib.GetYear;
	Y = lib.GetYear; -- Screw ISO-8610, it confuses me.
	y = lib.GetYearShortFormatted;

	a = lib.GetamOrpm;
	A = lib.GetAMorPM;
	--B -- No one uses it
	g = lib.GetRegularHour;
	G = lib.GetHour;
	h = lib.GetRegularHourFormatted;
	H = lib.GetHourFormatted;
	i = lib.GetFormattedMinute;
	s = lib.GetFormattedSecond;

	X = lib.GetJulianDate; -- For testing purposes.

	-- e -- No way to get Time Zones
	-- I -- Daylight saving time should be added later.
	-- O -- No way to get Time Zones
	-- P -- No way to get Time Zones
	-- T -- No way to get Time Zones
	-- Z -- No way to get Time Zones

	-- c -- ISO 8601
	-- r -- No need for formatted dates
	U = time;
}

local MatchString = "[" do
	for Index, Value in pairs(ISO_FORMAT_STRINGS) do
		MatchString = MatchString .. Index
	end
	MatchString = MatchString .. "]"
end

function lib.GetFormattedTime(Format, CurrentTime)
	CurrentTime = CurrentTime or tick()

	local ReturnString = Format
	local FormatsRequired = {}

	for NewFormat in string.gmatch(Format, MatchString) do
		FormatsRequired[#FormatsRequired+1] = NewFormat
	end

	for _, FormatType in pairs(FormatsRequired) do
		ReturnString = ReturnString:gsub(FormatType, FormatType:rep(3))
	end

	for _, FormatType in pairs(FormatsRequired) do
		local Replacement = ISO_FORMAT_STRINGS[FormatType](CurrentTime)
		ReturnString = ReturnString:gsub(FormatType:rep(3), Replacement)
	end

	return ReturnString
end

return lib