You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
278 lines
5.7 KiB
Lua
278 lines
5.7 KiB
Lua
--[=[
|
|
@c Time
|
|
@t ui
|
|
@mt mem
|
|
@d Represents a length of time and provides utilities for converting to and from
|
|
different formats. Supported units are: weeks, days, hours, minutes, seconds,
|
|
and milliseconds.
|
|
]=]
|
|
|
|
local class = require('class')
|
|
local constants = require('constants')
|
|
|
|
local MS_PER_S = constants.MS_PER_S
|
|
local MS_PER_MIN = MS_PER_S * constants.S_PER_MIN
|
|
local MS_PER_HOUR = MS_PER_MIN * constants.MIN_PER_HOUR
|
|
local MS_PER_DAY = MS_PER_HOUR * constants.HOUR_PER_DAY
|
|
local MS_PER_WEEK = MS_PER_DAY * constants.DAY_PER_WEEK
|
|
|
|
local insert, concat = table.insert, table.concat
|
|
local modf, fmod = math.modf, math.fmod
|
|
local isInstance = class.isInstance
|
|
|
|
local function decompose(value, mult)
|
|
return modf(value / mult), fmod(value, mult)
|
|
end
|
|
|
|
local units = {
|
|
{'weeks', MS_PER_WEEK},
|
|
{'days', MS_PER_DAY},
|
|
{'hours', MS_PER_HOUR},
|
|
{'minutes', MS_PER_MIN},
|
|
{'seconds', MS_PER_S},
|
|
{'milliseconds', 1},
|
|
}
|
|
|
|
local Time = class('Time')
|
|
|
|
local function check(self, other)
|
|
if not isInstance(self, Time) or not isInstance(other, Time) then
|
|
return error('Cannot perform operation with non-Time object', 2)
|
|
end
|
|
end
|
|
|
|
function Time:__init(value)
|
|
self._value = tonumber(value) or 0
|
|
end
|
|
|
|
function Time:__tostring()
|
|
return 'Time: ' .. self:toString()
|
|
end
|
|
|
|
--[=[
|
|
@m toString
|
|
@r string
|
|
@d Returns a human-readable string built from the set of normalized time values
|
|
that the object represents.
|
|
]=]
|
|
function Time:toString()
|
|
local ret = {}
|
|
local ms = self:toMilliseconds()
|
|
for _, unit in ipairs(units) do
|
|
local n
|
|
n, ms = decompose(ms, unit[2])
|
|
if n == 1 then
|
|
insert(ret, n .. ' ' .. unit[1]:sub(1, -2))
|
|
elseif n > 0 then
|
|
insert(ret, n .. ' ' .. unit[1])
|
|
end
|
|
end
|
|
return #ret > 0 and concat(ret, ', ') or '0 milliseconds'
|
|
end
|
|
|
|
function Time:__eq(other) check(self, other)
|
|
return self._value == other._value
|
|
end
|
|
|
|
function Time:__lt(other) check(self, other)
|
|
return self._value < other._value
|
|
end
|
|
|
|
function Time:__le(other) check(self, other)
|
|
return self._value <= other._value
|
|
end
|
|
|
|
function Time:__add(other) check(self, other)
|
|
return Time(self._value + other._value)
|
|
end
|
|
|
|
function Time:__sub(other) check(self, other)
|
|
return Time(self._value - other._value)
|
|
end
|
|
|
|
function Time:__mul(other)
|
|
if not isInstance(self, Time) then
|
|
self, other = other, self
|
|
end
|
|
other = tonumber(other)
|
|
if other then
|
|
return Time(self._value * other)
|
|
else
|
|
return error('Cannot perform operation with non-numeric object')
|
|
end
|
|
end
|
|
|
|
function Time:__div(other)
|
|
if not isInstance(self, Time) then
|
|
return error('Division with Time is not commutative')
|
|
end
|
|
other = tonumber(other)
|
|
if other then
|
|
return Time(self._value / other)
|
|
else
|
|
return error('Cannot perform operation with non-numeric object')
|
|
end
|
|
end
|
|
|
|
--[=[
|
|
@m fromWeeks
|
|
@t static
|
|
@p t number
|
|
@r Time
|
|
@d Constructs a new Time object from a value interpreted as weeks, where a week
|
|
is equal to 7 days.
|
|
]=]
|
|
function Time.fromWeeks(t)
|
|
return Time(t * MS_PER_WEEK)
|
|
end
|
|
|
|
--[=[
|
|
@m fromDays
|
|
@t static
|
|
@p t number
|
|
@r Time
|
|
@d Constructs a new Time object from a value interpreted as days, where a day is
|
|
equal to 24 hours.
|
|
]=]
|
|
function Time.fromDays(t)
|
|
return Time(t * MS_PER_DAY)
|
|
end
|
|
|
|
--[=[
|
|
@m fromHours
|
|
@t static
|
|
@p t number
|
|
@r Time
|
|
@d Constructs a new Time object from a value interpreted as hours, where an hour is
|
|
equal to 60 minutes.
|
|
]=]
|
|
function Time.fromHours(t)
|
|
return Time(t * MS_PER_HOUR)
|
|
end
|
|
|
|
--[=[
|
|
@m fromMinutes
|
|
@t static
|
|
@p t number
|
|
@r Time
|
|
@d Constructs a new Time object from a value interpreted as minutes, where a minute
|
|
is equal to 60 seconds.
|
|
]=]
|
|
function Time.fromMinutes(t)
|
|
return Time(t * MS_PER_MIN)
|
|
end
|
|
|
|
--[=[
|
|
@m fromSeconds
|
|
@t static
|
|
@p t number
|
|
@r Time
|
|
@d Constructs a new Time object from a value interpreted as seconds, where a second
|
|
is equal to 1000 milliseconds.
|
|
]=]
|
|
function Time.fromSeconds(t)
|
|
return Time(t * MS_PER_S)
|
|
end
|
|
|
|
--[=[
|
|
@m fromMilliseconds
|
|
@t static
|
|
@p t number
|
|
@r Time
|
|
@d Constructs a new Time object from a value interpreted as milliseconds, the base
|
|
unit represented.
|
|
]=]
|
|
function Time.fromMilliseconds(t)
|
|
return Time(t)
|
|
end
|
|
|
|
--[=[
|
|
@m fromTable
|
|
@t static
|
|
@p t table
|
|
@r Time
|
|
@d Constructs a new Time object from a table of time values where the keys are
|
|
defined in the constructors above (eg: `weeks`, `days`, `hours`).
|
|
]=]
|
|
function Time.fromTable(t)
|
|
local n = 0
|
|
for _, v in ipairs(units) do
|
|
local m = tonumber(t[v[1]])
|
|
if m then
|
|
n = n + m * v[2]
|
|
end
|
|
end
|
|
return Time(n)
|
|
end
|
|
|
|
--[=[
|
|
@m toWeeks
|
|
@r number
|
|
@d Returns the total number of weeks that the time object represents.
|
|
]=]
|
|
function Time:toWeeks()
|
|
return self:toMilliseconds() / MS_PER_WEEK
|
|
end
|
|
|
|
--[=[
|
|
@m toDays
|
|
@r number
|
|
@d Returns the total number of days that the time object represents.
|
|
]=]
|
|
function Time:toDays()
|
|
return self:toMilliseconds() / MS_PER_DAY
|
|
end
|
|
|
|
--[=[
|
|
@m toHours
|
|
@r number
|
|
@d Returns the total number of hours that the time object represents.
|
|
]=]
|
|
function Time:toHours()
|
|
return self:toMilliseconds() / MS_PER_HOUR
|
|
end
|
|
|
|
--[=[
|
|
@m toMinutes
|
|
@r number
|
|
@d Returns the total number of minutes that the time object represents.
|
|
]=]
|
|
function Time:toMinutes()
|
|
return self:toMilliseconds() / MS_PER_MIN
|
|
end
|
|
|
|
--[=[
|
|
@m toSeconds
|
|
@r number
|
|
@d Returns the total number of seconds that the time object represents.
|
|
]=]
|
|
function Time:toSeconds()
|
|
return self:toMilliseconds() / MS_PER_S
|
|
end
|
|
|
|
--[=[
|
|
@m toMilliseconds
|
|
@r number
|
|
@d Returns the total number of milliseconds that the time object represents.
|
|
]=]
|
|
function Time:toMilliseconds()
|
|
return self._value
|
|
end
|
|
|
|
--[=[
|
|
@m toTable
|
|
@r number
|
|
@d Returns a table of normalized time values that represent the time object in
|
|
a more accessible form.
|
|
]=]
|
|
function Time:toTable()
|
|
local ret = {}
|
|
local ms = self:toMilliseconds()
|
|
for _, unit in ipairs(units) do
|
|
ret[unit[1]], ms = decompose(ms, unit[2])
|
|
end
|
|
return ret
|
|
end
|
|
|
|
return Time
|