I have this function:
function SecondsFormat(X)
if X <= 0 then return "" end
local t ={}
local ndays = string.format("%02.f",math.floor(X / 86400))
if tonumber(ndays) > 0 then table.insert(t,ndays.."d ") end
local nHours = string.format("%02.f",math.floor((X/3600) -(ndays*24)))
if tonumber(nHours) > 0 then table.insert(t,nHours.."h ") end
local nMins = string.format("%02.f",math.floor((X/60) - (ndays * 1440) - (nHours*60)))
if tonumber(nMins) > 0 then table.insert(t,nMins.."m ") end
local nSecs = string.format("%02.f", math.fmod(X, 60));
if tonumber(nSecs) > 0 then table.insert(t,nSecs.."s") end
return table.concat(t)
end
I would like to add weeks and months to it but cant get my head around the month part to move on to the week part just because the days in a month aren't always the same so can anyone offer some help?
The second question is, is using a table to store the results the most efficient way of dealing with this given the function will be called every 3 seconds for up to 100 items (in a grid)?
Edit:
function ADownload.ETA(Size,Done,Tranrate) --all in bytes
if Size == nil then return "--" end
if Done == nil then return "--" end
if Tranrate == nil then return "--" end
local RemS = (Size - Done) / Tranrate
local RemS = tonumber(RemS)
if RemS <= 0 or RemS == nil or RemS > 63072000 then return "--" end
local date = os.date("%c",RemS)
if date == nil then return "--" end
local month, day, year, hour, minute, second = date:match("(%d+)/(%d+)/(%d+) (%d+): (%d+):(%d+)")
month = month - 1
day = day - 1
year = year - 70
if tonumber(year) > 0 then
return string.format("%dy %dm %dd %dh %dm %ds", year, month, day, hour, minute, second)
elseif tonumber(month) > 0 then
return string.format("%dm %dd %dh %dm %ds",month, day, hour, minute, second)
elseif tonumber(day) > 0 then
return string.format("%dd %dh %dm %ds",day, hour, minute, second)
elseif tonumber(hour) > 0 then
return string.format("%dh %dm %ds",hour, minute, second)
elseif tonumber(minute) > 0 then
return string.format("%dm %ds",minute, second)
else
return string.format("%ds",second)
end
end
I merged the function into the main function as I figured it would probably be quicker but I now have two questions:
1: I had to add
if date == nil then return "--" end
because it errors occasionally with date:match trying to compare with "nil" however os.date mentions nothing in the literature about returning nil as its a string or a table so although the extra line of code fixes the issue I'm wondering why that behaviour occurs as I'm sure I caught all the non events in the previous returns?
2: Sometimes I see functions written like myfunction(...) and I'm sure that just does away with the arguments and if so is there a one line of code that could do away with the first 3 "if" statements?
You can use the os.date function to get date values in a useable format. The '*t' formating parameter makes the returned date into a table instead of a string.
local t = os.date('*t')
print(t.year, t.month, t.day, t.hour, t.min, t.sec)
print(t.wday, t.yday)
os.data uses the current time by default, you can pass it an explicit time if you want (see the os.data docs for more info on this)
local t = os.date('*t', x)
As for table performance, I wouldn't worry about that. Not only is your function not called all that often, but table handling is much cheaper than other things you might be doing (calling os.date, lots of string formatting, etc)
Why not let Lua's os library do the hard work for you?
There is probably an easier (read: better) way to figure out the difference to 01/01/70, but here is a quick idea of how you could use it:
function SecondsFormat(X)
if X <= 0 then return "" end
local date = os.date("%c", X) -- will give something like "01/03/70 03:40:00"
local inPattern = "(%d+)/(%d+)/(%d+) (%d+):(%d+):(%d+)"
local outPattern = "%dy %dm %dd %dh %dm %ds"
local month, day, year, hour, minute, second = date:match(inPattern)
month = month - 1
day = day - 1
year = year - 70
return string.format(outPattern, year, month, day, hour, minute, second)
end
I think that this should also be a lot quicker than constructing the table and calling string.format multiple times - but you'd have to profile that.
EDIT: I ran a quick test with two functions that concatenate "abc", "def" and "ghi" using both methods. Inserting those strings into a table an concatenating took 14 seconds (for several million runs of course) and using a single string.format() took 6 seconds. This does not take into account, that your code calls string.format() anyway (multiple times) - nor the difference between you figuring out the values by division and I by pattern matching. Pattern matching is certainly slower, but I doubt that it outweighs the gains from not having a table - and it's certainly convenient to be able to leverage os.time(). The fastest way would probably be figuring out the month and day manually and then using a single string.format(). But again - you'd have to profile that.
EDIT2: missingno has a good point with using the "*t" option with os.date to give you the values separately in the first place. Again, this depends on whether you want to have a table for convenience vs. a string for storage or whatever reasons. Combining "*t" and a single string.format:
function SecondsFormat(X)
if X <= 0 then return "" end
local date = os.date("*t", X) -- will give you a table
local outPattern = "%dy %dm %dd %dh %dm %ds"
date.month = date.month - 1
date.day = date.day - 1
date.year = date.year - 70
return string.format(outPattern, date.year, date.month, date.day, date.hour, date.min, date.sec)
end
Related
I’m pretty new to scripting or coding and I’m trying to figure out a way to have an input that can be between 1 and 100 without having to write 100 lines of code. I am doing this in Lua and I will include my current lines below.
elseif input.text == '>coins add 100' then coins = coins + 100; print ("coins effected. "..coins)
elseif input.text == '>coins add 200' then coins = coins + 200; print ("coins effected. "..coins)
elseif input.text == '>coins add 300' then coins = coins + 300; print ("coins effected. "..coins)
I’m using this for a game I’m developing because i thought it would be a good way to practice. This in specific is for a console to change different values for debugging. Tell me if this doesn’t make sense and i will try to fix it.
Thanks!
The function that limits a number in a certain range usually called Clamp.
function math.Clamp(val, min, max)
return math.min(math.max(val, min), max)
end
It's basically and literally a math.max with math.min together.
To avoid 100 if statements, I suggest you to make a script to wait for >coins add and then ask for a number specifically.
[Edit] Apparently it doesn't allow you to do so, so here is a walkaround:
local num = string.sub(input.text, 12) -- remove 12 first characters from the string, this will leave a number in it
num = tonumber(num) -- convert a string into Lua number
if not num then -- if the conversion failed, stop the script, print the text
print("Not a number")
return
end
num = math.Clamp(num, 1, 100) -- Limit the number from 1 to 100
coins = coins + num -- add that number
print ("coins effected. " .. coins) -- New amount of coins
So I am just tinkering with Lua after hearing that it was more versatile than python, so I tried to make a countdown to one year, in the form of DDD:HR:MN:SC. If anyone could give me an example it would be much appreciated!
Following code should exactly do what you want:
local function sleep(s)
local t = os.clock() + s
repeat until os.clock() > t
end
local function getDiff(t)
return os.difftime(t, os.time())
end
local function dispTime(t)
local d = math.floor(t / 86400)
local h = math.floor((t % 86400) / 3600)
local m = math.floor((t % 3600) / 60)
local s = math.floor((t % 60))
return string.format("%d:%02d:%02d:%02d", d, h, m, s)
end
local function countdown(tTbl)
local diff = getDiff(os.time(tTbl))
repeat
print(dispTime(diff))
-- os.execute('echo ' .. dispTime(diff))
sleep(1)
diff = getDiff(os.time(tTbl))
until (diff <= 0)
end
countdown{
day = 24,
month = 12,
year = 2019,
hour = 0,
min = 0,
sec = 0
}
You can use os.date to retreive the current date as a table, then just build the difference by subtracting component-wise like this:
local function print_remaining(target)
local current = os.date("*t")
print(string.format("%i years, %i months and %i days",
target.year-current.year,
target.month-current.month,
target.day-current.day
))
end
local function countdown(target)
while true do
print_remaining(target)
os.execute('sleep 1')
end
end
countdown {year = 2019, month=12, day=25}
If you want it to be cooler, of course you'd have to adjust what components are shown depending on how much time is left.
Inspired by #csaars answer, I changed a few things and ended up with this
local function split(full, step, ...)
if step then
return math.floor(full % step), split(math.floor(full / step), ...)
else
return full
end
end
local function countdown(target)
local s, m, h, d = split(os.difftime(os.time(target), os.time()), 60, 60, 24)
print(string.format("%i days, %i:%i:%i", d, h, m, s))
if os.execute('sleep 1') then
return countdown(target)
end
end
countdown {year = 2019, month=12, day=25}
The plit function is a bit more complex than it needs to be for this example, but I thought it'd be a nice chance to showcase how nicely some things can be expressed with variadic recursive functions in Lua.
Just make sure that the countdown isn't past January 19, 2038. Unix Time won't work past that. Integer Overflow is the problem.
To obtain detailed information about the date, use the function os.date with the string argument "*t". This call returns a table containing information such as minute, day, year, etc.
Using this, you could write a simple function that retrieves the current date and formats it however you prefer. In this example, I went with the yyyy/mm/dd format.
function format_date()
local function tbl = os.date("*t")
local date = string.format("%d/%d/%d", t.year, t.month, t.day)
return date
end
print(format_date())
> 2019/11/19
The function os.time returns the time in seconds since the beginning of the current epoch. This could be another way to produce a countdown timer.
Here is a link to a page about the Lua OS library.
I want to know if you can get the date difference of two dates that are predefined or dynamic in a long run.
Do you need a proper date format when using this function?
function datediff(d1, d2, ...)
col_date1 = os.time({year = d1:year(), month = d1:month(), day = d1:day() , hour = d1:hour(), min = d1:minute(), sec = d1:second() })
col_date2 = os.time({year = d2:year(), month = d2:month(), day = d2:day() , hour = d2:hour(), min = d2:minute(), sec = d2:second() })
local arg={...}
if arg[1] ~= nil then
if arg[1] == "min" then
return math.abs((col_date1 - col_date2) / 60)
elseif arg[1] == "hour" then
return math.abs((col_date1 - col_date2) / 3600)
elseif arg[1] == "day" then
return math.abs((col_date1 - col_date2) / 86400)
end
end
return math.abs(col_date1 - col_date2)
--return 0
end
This is the code. But I have no idea how this work exactly.
The input should be like 31122017 - 31122016 is 1 year. or something like that.
This code takes custom date objects as input. So, for example, if you had a date object d that represented a date like 2017-05-22, then calling d:year() would give you the number 2017, d:hour() would give you the number 5, etc.
There are no functions to make objects like this in standard Lua, so the project this code is in must be using a separate date library. You need to find out how to create the date objects that your project expects, and then pass those into the function.
Let's assume I have the following reminder timestamp
local reminder_timestamp = "2013-12-13T00:00:00+01:00"
And I'm using the below function to return time in UTC
local function makeTimeStamp(dateString)
local pattern = "(%d+)%-(%d+)%-(%d+)%a(%d+)%:(%d+)%:([%d%.]+)([Z%p])(%d%d)%:?(%d%d)"
local year, month, day, hour, minute, seconds, tzoffset, offsethour, offsetmin = dateString:match(pattern)
local timestamp = os.time( {year=year, month=month, day=day, hour=hour, min=minute, sec=seconds} )
local offset = 0
if ( tzoffset ) then
if ( tzoffset == "+" or tzoffset == "-" ) then -- we have a timezone!
offset = offsethour * 60 + offsetmin
if ( tzoffset == "-" ) then
offset = offset * -1
end
timestamp = timestamp + offset
end
end
return timestamp
end
What should be the pattern above to match the reminder timestamp I mentioned earlier?
You need to use Lua's string parsing capabilities. Try a few of the techniques mentioned in the following, and if you still have issues, post specifically what is not working:
Question about splitting string and saving in several variables
Question about extracting data from a string, very similar to yours (although problem domain is GPS coordinates instead of date/time)
Question about how to do pattern matching in Lua, several good examples and links to docs
Here is the answer and the function actually works fine
pattern = "(%d+)%-(%d+)%-(%d+)%a(%d+)%:(%d+)%:([%d%.]+)([Z%p])(%d%d)%:?(%d%d)"
reminder_timestamp = "2013-12-23T08:00:00+01:00"
local year, month, day, hour, minute, seconds, tzoffset, offsethour, offsetmin = reminder_timestamp:match(pattern)
Resource: http://www.lua.org/manual/5.1/manual.html#5.4.1
Is there a way to convert human readable time "09:41:43" to some comparable format?
What I want is function timeGreater(time1, time2), satisfied the below assertion
assert(true == timeGreater("09:41:43", "09:00:42"))
assert(false == timeGreater("12:55:43", "19:00:43")))
It seems like a simple string comparison may be sufficient (assuming time is valid):
function timeGreater(a, b) return a > b end
assert(true == timeGreater("09:41:43", "09:00:42"))
assert(false == timeGreater("12:55:43", "19:00:43"))
Converting your time to seconds should work. The code below might work, LUA isn't my strong suit!
function stime(s)
local pattern = "(%d+):(%d+):(%d+)"
local hours, minutes, seconds = string.match(s, pattern)
return (hours*3600)+(minutes*60)+seconds
end
function timeGreater(a, b)
return stime(a) > stime(b)
end