Module:TimeSpan

From Melvor Idle
Revision as of 21:29, 13 April 2024 by Ricewind (talk | contribs) (Correct toStringLong missing milliseconds)

TimeSpan Module Documentation

The 'TimeSpan' module provides functionality for working with time spans in Lua.

Constructor

TimeSpan.new(days, hours, minutes, seconds, milliseconds)

Creates a new 'TimeSpan' object representing the specified time components.

  • Parameters:
 * `'days'`: Number of days (default: `0`).
 * `'hours'`: Number of hours (default: `0`).
 * `'minutes'`: Number of minutes (default: `0`).
 * `'seconds'`: Number of seconds (default: `0`).
 * `'milliseconds'`: Number of milliseconds (default: `0`).
  • Returns: 'TimeSpan' object.

TimeSpan.fromSeconds(seconds)

Creates a new 'TimeSpan' object from a total number of seconds.

  • Parameters:
 * `'seconds'`: Total number of seconds.
  • Returns: 'TimeSpan' object representing the specified duration in seconds.

TimeSpan.fromMilliseconds(milliseconds)

Creates a new 'TimeSpan' object from a total number of milliseconds.

  • Parameters:
 * `'milliseconds'`: Total number of milliseconds.
  • Returns: 'TimeSpan' object representing the specified duration in milliseconds.

Methods

TimeSpan:getDays()

Gets the number of days in the 'TimeSpan'.

  • Returns: Number of days as an integer.

TimeSpan:getHours()

Gets the number of hours in the 'TimeSpan'.

  • Returns: Number of hours as an integer.

TimeSpan:getMinutes()

Gets the number of minutes in the 'TimeSpan'.

  • Returns: Number of minutes as an integer.

TimeSpan:getSeconds()

Gets the number of seconds in the 'TimeSpan'.

  • Returns: Number of seconds as an integer.

TimeSpan:getMilliseconds()

Gets the number of milliseconds in the 'TimeSpan'.

  • Returns: Number of milliseconds as an integer.

TimeSpan:totalDays()

Gets the total number of days represented by the 'TimeSpan' (including fractional days).

  • Returns: Total number of days as a floating-point number.

TimeSpan:totalHours()

Gets the total number of hours represented by the 'TimeSpan' (including fractional hours).

  • Returns: Total number of hours as a floating-point number.

TimeSpan:totalMinutes()

Gets the total number of minutes represented by the 'TimeSpan' (including fractional minutes).

  • Returns: Total number of minutes as a floating-point number.

TimeSpan:totalSeconds()

Gets the total number of seconds represented by the 'TimeSpan' (including fractional seconds).

  • Returns: Total number of seconds as a floating-point number.

TimeSpan:totalMilliseconds()

Gets the total number of milliseconds represented by the 'TimeSpan' (including fractional milliseconds).

  • Returns: Total number of milliseconds as a floating-point number.

TimeSpan:toString()

Converts the 'TimeSpan' object to a string representation.

  • Returns: String representation of the 'TimeSpan' in the format `'d.hh:mm:ss.fff'`, where `'d'` is days, `'hh'` is hours, `'mm'` is minutes, `'ss'` is seconds, and `'fff'` is milliseconds.

Example Usage

To use the 'TimeSpan' module in your Lua scripts, follow these examples:

local TimeSpan = require('TimeSpan')

-- Create a new TimeSpan representing 1 day, 2 hours, 30 minutes, 15 seconds, and 500 milliseconds
local ts = TimeSpan.new(1, 2, 30, 15, 500)

-- Get the string representation of the TimeSpan
local tsString = ts:toString()

-- Output the TimeSpan string representation
print(tsString)  -- Output: "1.02:30:15.500"

-- Get specific components of the TimeSpan
print("Days:", ts:getDays())  -- Output: 1
print("Hours:", ts:getHours())  -- Output: 2
print("Minutes:", ts:getMinutes())  -- Output: 30
print("Seconds:", ts:getSeconds())  -- Output: 15
print("Milliseconds:", ts:getMilliseconds())  -- Output: 500

-- Get the total number of hours represented by the TimeSpan
local totalHours = ts:totalHours()
print("Total Hours:", totalHours)  -- Output: 26.507638888889

-- Get the total number of minutes represented by the TimeSpan
local totalMinutes = ts:totalMinutes()
print("Total Minutes:", totalMinutes)  -- Output: 1590.4583333333

local TimeSpan = {}

local StringBuilder = require('Module:StringBuilder')

-- Metatable to make instances of TimeSpan readonly
local TimeSpan_mt = {
    __index = TimeSpan,
    __newindex = function()
        error("Attempt to modify readonly TimeSpan", 2)
    end
}

local MillisecondsPerSecond =	1000
local MillisecondsPerMinute =	60000
local MillisecondsPerHour = 	3600000
local MillisecondsPerDay =  	86400000
 
local SecondsPerMinute =		60
local SecondsPerHour =			3600
local SecondsPerDay =			86400
 
local MinutesPerHour =			60
local MinutesPerDay =			1440 
 
local HoursPerDay = 			24     

function TimeSpan.new(days, hours, minutes, seconds, milliseconds)
    local totalMilliseconds =  (days or 0)	  *	MillisecondsPerDay +
                               (hours or 0)   *	MillisecondsPerHour +
                               (minutes or 0) * MillisecondsPerMinute +
                               (seconds or 0) * MillisecondsPerSecond +
                               (milliseconds or 0)

    local self = {
        _totalMilliseconds = totalMilliseconds
    }

    setmetatable(self, TimeSpan_mt)
    return self
end

function TimeSpan.fromMilliseconds(milliseconds)
    return TimeSpan.new(0, 0, 0, 0, (milliseconds or 0))
end

function TimeSpan.fromSeconds(seconds)
    local totalMilliseconds = (seconds or 0) * MillisecondsPerSecond
    return TimeSpan.new(0, 0, 0, 0, totalMilliseconds)
end

function TimeSpan:getDays()
    return math.floor(self._totalMilliseconds / MillisecondsPerDay)
end

function TimeSpan:getHours()
    return math.floor(self._totalMilliseconds / MillisecondsPerHour % HoursPerDay)
end

function TimeSpan:getMinutes()
    return math.floor(self._totalMilliseconds / MillisecondsPerMinute % MinutesPerHour)
end

function TimeSpan:getSeconds()
    return math.floor(self._totalMilliseconds / MillisecondsPerSecond % SecondsPerMinute)
end

function TimeSpan:getMilliseconds()
    return math.floor(self._totalMilliseconds % MillisecondsPerSecond)
end

function TimeSpan:getTotalDays()
	return self._totalMilliseconds / MillisecondsPerDay
end

function TimeSpan:getTotalHours()
	return self._totalMilliseconds / MillisecondsPerHour
end

function TimeSpan:getTotalMinutes()
	return self._totalMilliseconds / MillisecondsPerMinute
end

function TimeSpan:getTotalSeconds()
	return self._totalMilliseconds / MillisecondsPerSecond
end

function TimeSpan:getTotalMilliseconds()
	return self._totalMilliseconds
end

function TimeSpan:toString()
	local sb = StringBuilder.new()
	local days = self:getDays()
	local hours = self:getHours()
	local minutes = self:getMinutes()
	local seconds = self:getSeconds()

    if days > 0 then
        sb:append(string.format("%d.", days))
    end
    
    sb:append(string.format("%02d:%02d:%02d", hours, minutes, seconds))
    
    if milliseconds > 0 then
        sb:append(string.format(".%03d", milliseconds))
    end

    return sb:toString()
end

function TimeSpan:toStringLong()
	-- Fast path if there's less than a minute's worth of time.
	local totalSeconds = self:getTotalSeconds()
	if totalSeconds < 60 then
		if math.floor(totalSeconds) == 0 then
			return string.format('0 seconds')
		end
		
		return string.format('%.1f seconds', totalSeconds)
	end

	-- Long path that outputs the entire TimeSpan
	local output = {}
	local days = self:getDays()
	local hours = self:getHours()
	local minutes = self:getMinutes()
	local seconds = self:getSeconds()
	local milliseconds = self:getMilliseconds()

	if days > 0 then
		table.insert(output, string.format('%d day%s', days, (days > 1) and "s" or ""))
	end
	if hours > 0 then
		table.insert(output, string.format('%d hour%s', hours, (hours > 1) and "s" or ""))
	end
	if minutes > 0 then
		table.insert(output, string.format('%d minute%s', minutes, (minutes > 1) and "s" or ""))
	end
	if seconds > 0 then
		table.insert(output, string.format('%d second%s', seconds, (seconds > 1) and "s" or ""))
	end
	if milliseconds > 0 then
		table.insert(output, string.format('%d milliseconds%s', milliseconds, (milliseconds > 1) and "s" or ""))
	end
	
	return table.concat(output, ", ")
end

function TimeSpan:__tostring()
    return self:toString()
end

return TimeSpan