Can I use os.date to convert seconds to time format? - lua

I need a simple function to convert seconds into a time string that humans can read to represent the countdown. I can get the results what I need through very intuitive mathematical calculations, but not elegant enough.
Then I noticed that there is a function named os.date, but I can't get the result I want, what is wrong with my calling, here is my code:
#!usr/bin/env lua
local function getDate1(sec)
local days = math.floor(sec / 86400)
local hours = math.floor((sec % 86400) / 3600)
local minutes = math.floor((sec % 3600) / 60)
local seconds = math.floor(sec % 60)
return days, hours, minutes, seconds
end
local function getDate2(sec)
local date = os.date("*t", sec)
return date["day"], date["hour"], date["min"], date["sec"]
end
local function printDate(d, h, m, s)
print(string.format("%02d %02d:%02d:%02d", d, h, m, s))
end
function main()
printDate(getDate1(999999))
printDate(getDate2(999999))
end
main()
11 13:46:39
12 21:46:39

local function getDate2(sec)
local date = os.date("!*t", sec)
return date["day"]-1, date["hour"], date["min"], date["sec"]
end

Related

add days to given timestamp (YYYY-mm-dd HH:MM:SS.sss) in lua script

Summary
I would like to add 1 day to given timestamp in lua script.
My try
local creation_date = "2016-01-01 00:00:00.000"
local y, m, d, Hr, Min, Sec, Milli = creation_date:match '(%d+)-(%d+)-(%d+) (%d+):(%d+):(%d+).(%d+)'
local dt = y .. '-' .. m .. '-'..d.. ' '..Hr..':'..Min..'-'..Sec..'.'..Milli
print(dt)
local new_ts = os.time
{ year = y, month = m, day = d,
hour = Hr, min = Min, sec = Sec, mill=Milli } + 1*24*60*60
print(new_ts)
I am getting new_ts = 1452470400
Expected result
2016-01-01 00:01:00.000 (in this format only)
The closest you may be able to get is something like this:
local creation_date = "2016-01-01 00:00:00.000"
local y, m, d, Hr, Min, Sec, Milli = creation_date:match '(%d+)-(%d+)-(%d+) (%d+):(%d+):(%d+).(%d+)'
local dt = y .. '-' .. m .. '-'..d.. ' '..Hr..':'..Min..'-'..Sec..'.'..Milli
print(dt)
local new_ts = os.time { year = y, month = m, day = d, hour = Hr, min = Min, sec = Sec } + 1*24*60*60
print(string.format("%s.%03d", os.date("%Y-%m-%d %H:%M:%S", new_ts), Milli))
The Mill entry in the table that you pass on to os.time() is being ignored, and the resulting value doesn't provide millisecond precision, so there's no point in including it. To get the format you desire, you need os.date() with an appropriate format, and then you can append the milliseconds to that again, manually.
With that, it looks like this:
$ lua script.lua
2016-01-01 00:00-00.000
2016-01-02 00:00:00.000
With the suggestion from #Nifim it can be simplified further, confirmed by the documentation
When the function is called, the values in these fields do not need to be inside their valid ranges. For instance, if sec is -10, it means 10 seconds before the time specified by the other fields; if hour is 1000, it means 1000 hours after the time specified by the other fields. - Lua 5.4 Reference Manual: os.time
local creation_date = "2016-01-31 00:00:00.000"
local y, m, d, Hr, Min, Sec, Milli = creation_date:match '(%d+)-(%d+)-(%d+) (%d+):(%d+):(%d+).(%d+)'
local dt = y .. '-' .. m .. '-'..d.. ' '..Hr..':'..Min..'-'..Sec..'.'..Milli
print(dt)
local new_ts = os.time { year = y, month = m, day = d + 1, hour = Hr, min = Min, sec = Sec }
print(string.format("%s.%03d", os.date("%Y-%m-%d %H:%M:%S", new_ts), Milli))
Output:
$ lua script.lua
2016-01-31 00:00-00.000
2016-02-01 00:00:00.000

math operations with hours,minutes and seconds

I work with decimal times in Lua and make arithmetical operations on them.
For example 124500+5=124505 (12:45:05)
What formula can avoid 60 digits problem?
124459+5=124504 (not 124464)
How can I resolve it?
You are mixing formation with calculation. The best way is to transform your time "string" in a real number:
12:45:05 -> 12 * 60 * 60 + 45 * 60 + 05 = 45905
The function could look like this:
function time_to_number(t)
return (math.floor(t / 10000) * 60 * 60) + ((math.floor(t / 100) % 100) * 60) + (t % 100)
-- you can also use % 10000 if the hours are limited to two digits
end
Now you can calculate on the seconds.
To format the value back you can use this function
function time_split(t)
local hour = math.floor(t / 3600)
local min = math.floor((t % 3600) / 60)
local sec = (t % 3600) % 60
return hour, min, sec
end
I have used many brackets for readability, which are not all required.

This code causes Corona to become unresponsive

When I run this code in Corona on Windows 7 it instantly crashes. It works fine in ZeroBrane. Any ideas why?
--Stopwatch--
local startTime
function start()
startTime = os.time()
--Start the stop watch--
end
function secondsEllapsed()
--Return the number of seconds since the stop watch was started--
return os.time() - startTime
end
start()
while true do
-- Get the time ellapsed and convert it to hours, minutes and seconds
ellapsed = secondsEllapsed()
hours = math.floor(ellapsed / 3600)
minutes = math.floor((ellapsed - (hours * 3600)) / 60)
seconds = math.floor((ellapsed - (hours * 3600) - (minutes * 60)))
-- Print the time ellapsed to the command line
print(hours .. 'h', minutes .. 'm', seconds .. 's')
end
It crashes probably because you run infinity loop.

Ruby Program time conversion

The task is to Write a method that will take in a number of minutes, and returns a string that formats the number into hours:minutes.
here's what I have so far:
def time_conversion(minutes)
minutes = (minutes / 60) % 60
hours = minutes / (60 * 60)
format(" %02d:%02d ", hours, minutes)
return format
end
it's not working out for me
Try this
def time_conversion(time)
minutes = time % 60
hours = time / 60
minutes = (minutes < 10)? "0" + minutes.to_s : minutes.to_s
return hours.to_s + ":" + minutes
end
Using division in Ruby returns a whole number, lowered to the previous number. Using modulus returns the remainder after division.
Ruby's Numeric#divmod is exactly what you want here. It returns both the quotient and remainder of a division operation, so e.g. 66.divmod(60) returns [ 1, 6 ]. Combined with sprintf (or String#%, it makes for an extremely simple solution:
def time_conversion(minutes)
"%02d:%02d" % minutes.divmod(60)
end
puts time_conversion(192)
# => 03:12
Well try
h = minutes/60
M = minutes%60

Ruby/Rails - How to convert seconds to time?

I need to perform the following conversion:
0 -> 12.00AM
1800 -> 12.30AM
3600 -> 01.00AM
...
82800 -> 11.00PM
84600 -> 11.30PM
I came up with this:
(0..84600).step(1800){|n| puts "#{n.to_s} #{Time.at(n).strftime("%I:%M%p")}"}
which gives me the wrong time, because Time.at(n) expects n to be number of seconds from epoch:
0 -> 07:00PM
1800 -> 07:30PM
3600 -> 08:00PM
...
82800 -> 06:00PM
84600 -> 06:30PM
What would be the most optimal, time zone independent solution for this transformation?
The simplest one-liner simply ignores the date:
Time.at(82800).utc.strftime("%I:%M%p")
#-> "11:00PM"
Not sure if this is better than
(Time.local(1,1,1) + 82800).strftime("%I:%M%p")
def hour_minutes(seconds)
Time.at(seconds).utc.strftime("%I:%M%p")
end
irb(main):022:0> [0, 1800, 3600, 82800, 84600].each { |s| puts "#{s} -> #{hour_minutes(s)}"}
0 -> 12:00AM
1800 -> 12:30AM
3600 -> 01:00AM
82800 -> 11:00PM
84600 -> 11:30PM
Stephan
Two offers:
The elaborate DIY solution:
def toClock(secs)
h = secs / 3600; # hours
m = secs % 3600 / 60; # minutes
if h < 12 # before noon
ampm = "AM"
if h = 0
h = 12
end
else # (after) noon
ampm = "PM"
if h > 12
h -= 12
end
end
ampm = h <= 12 ? "AM" : "PM";
return "#{h}:#{m}#{ampm}"
end
the Time solution:
def toClock(secs)
t = Time.gm(2000,1,1) + secs # date doesn't matter but has to be valid
return "#{t.strftime("%I:%M%p")} # copy of your desired format
end
HTH
In other solutions, the hour-counter would be reset to 00 when crossing 24-hour day boundaries. Also beware that Time.at rounds down, so it will give the wrong result if the input has any fractional seconds (f.ex. when t=479.9 then Time.at(t).utc.strftime("%H:%M:%S") will give 00:07:59 and not 00:08:00` which is the correct one).
If you want a way to convert any number of seconds (even high counts larger than 24-hour day spans) into an ever increasing HH:MM:SS counter, and handle potential fractional seconds, then try this:
# Will take as input a time in seconds (which is typically a result after subtracting two Time objects),
# and return the result in HH:MM:SS, even if it exceeds a 24 hour period.
def formatted_duration(total_seconds)
total_seconds = total_seconds.round # to avoid fractional seconds potentially compounding and messing up seconds, minutes and hours
hours = total_seconds / (60*60)
minutes = (total_seconds / 60) % 60 # the modulo operator (%) gives the remainder when leftside is divided by rightside. Ex: 121 % 60 = 1
seconds = total_seconds % 60
[hours, minutes, seconds].map do |t|
# Right justify and pad with 0 until length is 2.
# So if the duration of any of the time components is 0, then it will display as 00
t.round.to_s.rjust(2,'0')
end.join(':')
end
Modified from #springerigor's and suggestion in the discussion at https://gist.github.com/shunchu/3175001

Resources