Files
wnsrc/lua/niknaks/modules/sh_timedelta.lua
lifestorm 94063e4369 Upload
2024-08-04 22:55:00 +03:00

291 lines
8.1 KiB
Lua

--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- Copyright © 2022-2072, Nak, https://steamcommunity.com/id/Nak2/
-- All Rights Reserved. Not allowed to be reuploaded.
-- License: https://github.com/Nak2/NikNaks/blob/main/LICENSE
--- @class TimeDelta
--- @operator add:TimeDelta|DateTime
--- @operator sub:TimeDelta|DateTime
--- @operator mul:TimeDelta
--- @operator div:TimeDelta
--- @operator pow:TimeDelta
--- @operator mod:TimeDelta
local meta = {}
meta.__index = meta
meta.MetaName = "TimeDelta"
NikNaks.__metatables["TimeDelta"] = meta
--- @class TimeDeltaModule
--- @operator call:TimeDelta
local TimeDelta = {}
TimeDelta.Milisecond = 0.001
TimeDelta.Second = 1
TimeDelta.Minute = 60
TimeDelta.Hour = 3600
TimeDelta.Day = 86400
TimeDelta.Week = 604800
TimeDelta.Year = 31536000
TimeDelta.Decade = 315359654
TimeDelta.Century = 3153596543
TimeDelta._steps = { "Year", "Day", "Hour", "Minute", "Second", "Milisecond" }
setmetatable( TimeDelta, {
__index = TimeDelta,
__call = function( _, time )
return setmetatable( { time = time }, meta )
end
} )
NikNaks.TimeDelta = TimeDelta
do
local abs = math.abs
local floor = math.floor
local steps = TimeDelta._steps
--- Returns the time as a table
--- @return table
function meta:ToTable()
if self._tab then return self._tab end
local t = {}
local num = abs( self.time )
local f = self.time < 0 and -1 or 1
local isLeapYear = NikNaks.DateTime.IsLeapYear
local function processStep( i )
local step = steps[i]
local value = steps[step]
-- Leap year
if num < value then return end
if i == 1 then -- Since years aren't whole numbers, we need to round the tiniest amount, or floor is going to count down.
local n = 0
local y = TimeDelta.Year
local v = isLeapYear( y ) and 31622400 or 31536000
while num >= v do
local q = 1 * f
if num >= v then
n = n + 1
num = num - v
y = y + q
v = isLeapYear( y ) and 31622400 or 31536000
else
break
end
end
t[s] = n * f
else
local n = floor( num / v )
t[s] = n * f
num = num - v * n
end
end
for i = 1, #steps do
processStep( i )
end
self._tab = t
return t
end
end
-- Getters
do
--- Generic getter function to get the time amount of the given time type
--- @param key string The name of the time type to get
--- @return number
function meta:_getter( key )
return self.time / TimeDelta[key]
end
function meta:GetMiliseconds() return self:_getter( "Milisecond" ) end
function meta:GetSeconds() return self:_getter( "Second" ) end
function meta:GetMinutes() return self:_getter( "Minute" ) end
function meta:GetHours() return self:_getter( "Hour" ) end
function meta:GetDays() return self:_getter( "Day" ) end
function meta:GetWeeks() return self:_getter( "Week" ) end
function meta:GetMonths() return self:_getter( "Month" ) end
function meta:GetYears() return self:_getter( "Year" ) end
function meta:GetDecades() return self:_getter( "Decade" ) end
function meta:GetCenturies() return self:_getter( "Century" ) end
end
-- Adders
do
--- Generic adder function to add given time amount to the TimeDelta
--- @param key string The name of the time type to add
--- @param num number The amount of time to add
--- @return self TimeDelta
function meta:_adder( key, num )
self.time = self.time + ( num * TimeDelta[key] )
self._tab = nil
return self
end
--- @param n number
function meta:AddMiliseconds( n ) return self:_adder( "Milisecond", n ) end --- @param n number
function meta:AddSeconds( n ) return self:_adder( "Second", n ) end --- @param n number
function meta:AddMinutes( n ) return self:_adder( "Minute", n ) end --- @param n number
function meta:AddHours( n ) return self:_adder( "Hour", n ) end --- @param n number
function meta:AddDays( n ) return self:_adder( "Day", n ) end --- @param n number
function meta:AddWeeks( n ) return self:_adder( "Week", n ) end --- @param n number
function meta:AddMonths( n ) return self:_adder( "Month", n ) end --- @param n number
function meta:AddYears( n ) return self:_adder( "Year", n ) end --- @param n number
function meta:AddDecades( n ) return self:_adder( "Decade", n ) end --- @param n number
function meta:AddCenturies( n ) return self:_adder( "Century", n ) end --- @param n number
end
-- Subtractors
do
--- Generic subtractor function to subtract given time amount from the TimeDelta
--- @param key string The name of the time type to subtract
--- @param num number The amount of time to subtract
--- @return self TimeDelta
function meta:_subtractor( key, num )
self.time = self.time - ( num * TimeDelta[key] )
self._tab = nil
return self
end
function meta:SubMiliseconds( n ) return self:_subtractor( "Milisecond", n ) end --- @param n number
function meta:SubSeconds( n ) return self:_subtractor( "Second", n ) end --- @param n number
function meta:SubMinutes( n ) return self:_subtractor( "Minute", n ) end --- @param n number
function meta:SubHours( n ) return self:_subtractor( "Hour", n ) end --- @param n number
function meta:SubDays( n ) return self:_subtractor( "Day", n ) end --- @param n number
function meta:SubWeeks( n ) return self:_subtractor( "Week", n ) end --- @param n number
function meta:SubMonths( n ) return self:_subtractor( "Month", n ) end --- @param n number
function meta:SubYears( n ) return self:_subtractor( "Year", n ) end --- @param n number
function meta:SubDecades( n ) return self:_subtractor( "Decade", n ) end --- @param n number
function meta:SubCenturies( n ) return self:_subtractor( "Century", n ) end --- @param n number
end
-- ToString
do
local abs = math.abs
local steps = TimeDelta._steps
function meta:__tostring()
local str
local si = 0
local tab = self:ToTable()
local kv = #table.GetKeys( tab )
for i = 1, #steps do
local step = steps[i]
if tab[step] then
si = si + 1
local number = abs( tab[step] )
local middle = ( si == kv and " and " or ", " )
step = number == 1 and step or step .. "s"
if not str then
str = number .. " " .. step
else
str = str .. middle .. number .. " " .. step
end
end
end
return str or "nil"
end
end
function meta:IsNegative()
return self.time < 0
end
function meta:IsPositive()
return self.time >= 0
end
-- Operations
do
--- @param b TimeDelta|number
--- @return TimeDelta|DateTime
function meta:__add( b )
if isnumber( b ) then
return TimeDelta( self.time + b )
end
if self.unix and b.time then
return NikNaks.DateTime( self.unix + b.time )
elseif b.unix and self.time then
return NikNaks.DateTime( b.unix + self.time )
end
end
--- @param b TimeDelta|number
--- @return TimeDelta|DateTime
function meta:__sub( b )
if isnumber( b ) then
return TimeDelta( self.time - b )
end
if self.unix and b.time then
return NikNaks.DateTime( self.unix - b.time )
elseif b.unix and self.time then
return NikNaks.DateTime( b.unix - self.time )
end
end
--- @param b TimeDelta|number
--- @return TimeDelta
function meta:__mul( b )
b = isnumber( b ) and b or b.time
return TimeDelta( self.time * b )
end
--- @param b TimeDelta|number
--- @return TimeDelta
function meta:__div( b )
b = isnumber( b ) and b or b.time
return TimeDelta( self.time / b )
end
--- @param b TimeDelta|number
--- @return TimeDelta
function meta:__pow( b )
b = isnumber( b ) and b or b.time
return TimeDelta( self.time ^ b )
end
--- @param b TimeDelta|number
--- @return TimeDelta
function meta:__mod( b )
b = isnumber( b ) and b or b.time
return TimeDelta( self.time % b )
end
--- @param b TimeDelta
function meta:__eq( b )
return self.time == b.time
end
--- @param b TimeDelta
function meta:__lt( b )
return a.time < b.time
end
--- @param b TimeDelta
function meta.__le( b )
return a.time <= b.time
end
end