How can I add minutes and seconds to a datetime in lua? - time

I have a lua function to attempt to convert the time duration of the currently playing song e.g. hh:mm:ss to seconds.
function toSeconds (inputstr)
local mytable = string.gmatch(inputstr, "([^"..":".."]+)");
local conversion = { 60, 60, 24}
local seconds = 0;
--iterate backwards
local count = 0;
for i=1, v in mytable do
count = i+1
end
for i=1, v in mytable do
mytable[count-i]
seconds = seconds + v*conversion[i]
end
return seconds
end
in order to add it to os.time to get the estimated end time of a song.
but the hours may be missing, or the minutes may be missing on a short track.
When running against https://www.lua.org/cgi-bin/demo All I get is input:10: 'do' expected near 'in'
for the test script
function toSeconds (inputstr)
local mytable = string.gmatch(inputstr, "([^"..":".."]+)");
local conversion = { 60, 60, 24}
local seconds = 0;
--iterate backwards
local count = 0;
for i=1, v in mytable do
count = i+1
end
for i=1, v in mytable do
mytable[count-i]
seconds = seconds + v*conversion[i]
end
return seconds
end
print(toSeconds("1:1:1")

You're mixing up the two possible ways of writing a for loop:
a)
for i=1,10 do
print(i, "This loop is for counting up (or down) a number")
end
b)
for key, value in ipairs({"hello", "world"}) do
print(key, value, "This loop is for using an iterator function")
end
The first one, as you can see, simply counts up a number, i in this case. The second one is very generic and can be used to iterate over almost anything (for example using io.lines), but is most often used with pairs and ipairs to iterate over tables.
You also don't write for ... in tab, where tab is a table; you have to use ipairs for that, which then returns an iterator for the table (which is a function)
You're also using string.gmatch incorrectly; it doesn't return a table, but an iterator function over the matches of the pattern in the string, so you can use it like this:
local matches = {}
for word in some_string:gmatch("[^ ]") do
table.insert(matches, word)
end
which gives you an actual table containing the matches, but if you're only going to iterate over that table, you might as well use the gmatch loop directly.
for i=1, v in mytable do
count = i+1
end
I think you're just trying to count the elements in the table here? You can easily get the length of a table with the # operator, so #mytable
If you have a string like hh:mm:ss, but the hours and the minutes can be missing, the easiest thing might be to just fill them with 0. A somewhat hacky but short way to achieve this is to just append "00:00:" to your string, and look for the last 3 numbers in it:
local hours, minutes, seconds = ("00:00:"..inputstr):match("(%d%d):(%d%d):(%d%d)$")
If nothing is missing, you'll end up with something like 00:00:hh:mm:ss, which you only take the last 3 values of to end up with the correct time.

Related

I tried to shorten the code by removing assignments, but the result completely changed somehow., any explanation?

I tried this example code to see if it actually work
--This example is from Programming in Lua Second Edition
function values (t)
local i = 0
return function ()
i = i + 1
return t[i]
end
end
t = {10, 20, 30}
iter = values(t)
while true do
local element = iter()
-- calls the iterator
if element == nil then
break
end
print(element) --> 10, 20, 30
end
I decided to change it a bit, I thought the code will get the same result but I think I was wrong
--This example is from Programming in Lua Second Edition
function values (t)
local i = 0
return function ()
i = i + 1
return t[i]
end
end
t = {10, 20, 30}
while true do
local element = values(t)()
-- calls the iterator
if element == nil then
break
end
print(element) --> This will print 10 forever if I don't stop the IDE
end
Why is iter important that much?
When you do local element = values(t)(), you are actually creating an iterator function every single time your loop is running. Take a note of your values function, see that it has a local variable called i. Every single time you are running this function, a local variable is initialized and sent to your inner function which handles the iteration. The original example is perfectly fine, however if you want to practice local and global variables, you may change the local i to a global variable i, or a different name and move it outside your function so it will not get called every time you run your iterate function (You may keep it local still, so the scope will be limited to current file). However, that is totally not recommended, since your value may be re-used some time later by another function or file, also it will limit you to one full iteration per run (Unless you set the value back to zero before retrying to iterate.)
local i = 0 -- Notice that the variable is taken out of the function.
-- With your example, the problem was that this variable was set to 0 for every
-- time you called the function.
function values (t)
return function ()
i = i + 1
return t[i]
end
end
t = {10, 20, 30}
while true do
local element = values(t)()
-- calls the iterator
if element == nil then
break
end
print(element) --> This will print 10 forever if I don't stop the IDE
end
Also keep performance in your mind, as every time you are iterating with your example, a function is being created, called, and then destroyed by the garbage collection. This is why the original example created an iterator function only once, and then called it multiple times, whereas your example creates an iterator function every time it is looping.
If all you need to do is to iterate through elements of a table, then lua already has generic for loop (pairs), check here and here. Example in your case (which also shortens your code by a lot):
local t = {10, 20, 30}
-- We don't need key in this case, but if you do, replace _ with k or
-- any other variable name you want.
for _, element in pairs(t) do
print(element)
end

Lua - Create a nested table using for loop

I'm a very new to lua so am happy to read material if it will help with tables.
I've decoded a json object and would like to build a table properly using its data, rather than writing 64 lines of the below:
a = {}
a[decode.var1[1].aId] = {decode.var2[1].bId, decode.var3[1].cId}
a[decode.var1[2].aId] = {decode.var2[2].bId, decode.var3[2].cId}
a[decode.var1[3].aId] = {decode.var2[3].bId, decode.var3[3].cId}
...etc
Because the numbers are consecutive 1-64, i presume i should be able to build it using a for loop.
Unfortunately despite going through table building ideas I cannot seem to find a way to do it, or find anything on creating nested tables using a loop.
Any help or direction would be appreciated.
Lua for-loops are, at least in my opinion, pretty easy to understand:
for i = 1, 10 do
print(i)
end
This loop inclusively prints the positive integers 1 through 10.
Lua for-loops also take an optional third argument--which defaults to 1--that indicates the step of the loop:
for i = 1, 10, 2 do
print(i)
end
This loop prints the numbers 1 through 10 but skips every other number, that is, it has a step of 2; therefore, it will print 1 3 5 7 9.
In the case of your example, if I understand it correctly, it seems that you know the minimum and maximum bounds of your for loops, which are 1 and 64, respectively. You could write a loop to decode the values and put them in a table like so:
local a = {}
for i = 1, 64 do
a[decodevar.var1[i].aId] = {decode.var2[i].bId, decode.var3[i].cId}
end
What you can do is generating a new table with all the contents from the decoded JSON with a for loop.
For example,
function jsonParse(jsonObj)
local tbl = {}
for i = 1, 64 do
a[decodevar.var1[i].aId] = {decode.var2[i].bId, decode.var3[i].cId}
end
return tbl
end
To deal with nested cases, you can recursively call that method as follows
function jsonParse(jsonObj)
local tbl = {}
for i = 1, 64 do
a[decodevar.var1[i].aId] = {decode.var2[i].bId, decode.var3[i].cId}
if type(decode.var2[i].bId) == "table" then
a[decodevar.var1[i].aid[0] = jsonParse(decode.var2[i].bId)
end
end
end
By the way, I can't understand why are you trying to create a table using a table that have done the job you want already. I assume they are just random and you may have to edit the code with the structure of the decodevar variable you have

How to compare alternating rows in CSV using RUBY

I have a data set that consists thousand of rows. I would like to count how many times an alarm toggle between ALARM_OPENED and ALARM_NORMALIZED
Here is a data sample. The Alarm toggle twice and hence ideally the count = 2
The issue now is I cannot figure how to
1) compare ALARM _OPENED and ALARM_NORMALIZED for the event type
2) To compare the difference in time between the change in event (the toggling should happen within a time frame of two seconds.)
count = 0
#loop this
if event_type[0] = 'ALARM_OPENED'
if event_type[1] = 'ALARM_NORMALIZED'
#time[0] - time[1] = 2 seconds
count = count + 1
end
end
p count
If you can assume that you always have a bunch of OPENED/NORMALIZED pairs, you can slice the array into pairs:
event_type.each_slice(2) do |opened, normalized|
break unless normalized # unpaired event at the end
# whatever you want to do with the two events here
end

Random iteration to fill a table in Lua

I'm attempting to fill a table of 26 values randomly. That is, I have a table called rndmalpha, and I want to randomly insert the values throughout the table. This is the code I have:
rndmalpha = {}
for i= 1, 26 do
rndmalpha[i] = 0
end
valueadded = 0
while valueadded = 0 do
a = math.random(1,26)
if rndmalpha[a] == 0 then
rndmalpha[a] = "a"
valueadded = 1
end
end
while valueadded = 0 do
a = math.random(1,26)
if rndmalpha[a] == 0 then
rndmalpha[a] = "b"
valueadded = 1
end
end
...
The code repeats itself until "z", so this is just a general idea. The problem I'm running into, however, is as the table gets filled, the random hits less. This has potential to freeze up the program, especially in the final letters because there are only 2-3 numbers that have 0 as a value. So, what happens if the while loop goes through a million calls before it finally hits that last number? Is there an efficient way to say, "Hey, disregard positions 6, 13, 17, 24, and 25, and focus on filling the others."? For that matter, is there a much more efficient way to do what I'm doing overall?
The algorithm you are using seems pretty non-efficient, it seems to me that all you need is to initialize a table with all alphabet:
math.randomseed(os.time())
local t = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"}
and Then shuffle the elements:
for i = 1, #t*2 do
local a = math.random(#t)
local b = math.random(#t)
t[a],t[b] = t[b],t[a]
end
Swapping the elements for #t*2 times gives randomness pretty well. If you need more randomness, increase the number of shuffling, and use a better random number generator. The random() function provided by the C library is usually not that good.
Instead of randoming for each letter, go through the table once and get something random per position. The method you're using could take forever because you might never hit it.
Never repeat yourself. Never repeat yourself! If you're copy and pasting too often, it's a sure sign something has gone wrong. Use a second table to contain all the possible letters you can choose, and then randomly pick from that.
letters = {"a","b","c","d","e"}
numberOfLetters = 5
rndmalpha = {}
for i in 1,26 do
rndmalpha[i] = letters[math.random(1,numberOfLetters)]
end

UTC time resets to 2000-01-01 (ruby). How do I prevent the time from resetting?

I'm using a task and the spreadsheet gem to read in an excel spreadsheet into my database. One of the columns I'm reading in is "start_time." To do this, I'm forming an array of values, then passing in each of these array values, one by one.
cnum_array = [] # for start times
sheet1.each 3 do |row|
unless row[9].blank?
time = Time.parse(row[9])
cnum_array << time.utc
end
end
count = 0
for course in Course.all
course.update_attribute :start_time, cnum_array[count]
count += 1
end
This seems to work fine. If I insert a "puts course.start_time" statement within this last loop, it prints off the right time. Like so:
count = 0
for course in Course.all
course.update_attribute :start_time, cnum_array[count]
puts course.start_time
count += 1
end
This gives me the right time, e.g. "2012-01-23 15:30:00."
But when I look up the course time later (e.g. via my console's Course.find(1).start_time), it gives me "2000-01-01 15:20:00." So the time of day is right, but the day itself goes back to 2000-01-01.
Does anyone know why this is happening, and how I can fix it? Thanks!
You are using the Time class. This class deals with times, not dates. My guess is that your database column is of type time as well.
I recommend you use a datetime (or possibly timestamp) column type.

Resources