How do i format time into seconds in lua? - date

So basically I'm confused on how I'd make it so that I can convert DD:HH:MM:SS to only seconds while taking into account the amount of numbers there are. (Sorry if I make 0 sense, you should definitely know what I mean by the example below.)
print("05:00":FormatToSeconds()) -- 5 minutes and 0 seconds
-- 300
print("10:30:15":FormatToSeconds()) -- 10 hours, 30 minutes and 15 seconds
-- 37815
print("1:00:00:00":FormatToSeconds()) -- 1 day
-- 86400
print("10:00:00:30":FormatToSeconds()) -- 10 days, 30 seconds
-- 864030
So on and so forth. I think that maybe using gmatch would work but still idk. Help would be greatly appreciated.
Edit:
So I've tried doing it with gmatch, but I don't know if this is the most fastest way of doing this (which it probably isn't), so any help would still be appreciated.
(My code)
function ConvertTimeToSeconds(Time)
local Thingy = {}
local TimeInSeconds = 0
for v in string.gmatch(Time, "%d+") do
if tonumber(string.sub(v, 1, 1)) == 0 then
table.insert(Thingy, tonumber(string.sub(v, 2, 2)))
else
table.insert(Thingy, tonumber(v))
end
end
if #Thingy == 1 then
TimeInSeconds = TimeInSeconds + Thingy[1]
elseif #Thingy == 2 then
TimeInSeconds = TimeInSeconds + (Thingy[1] * 60) + Thingy[2]
elseif #Thingy == 3 then
TimeInSeconds = TimeInSeconds + (Thingy[1] * 60 * 60) + (Thingy[2] * 60) + Thingy[3]
elseif #Thingy == 4 then
TimeInSeconds = TimeInSeconds + (Thingy[1] * 24 * 60 * 60) + (Thingy[2] * 60 * 60) + (Thingy[3] * 60) + Thingy[4]
end
return TimeInSeconds
end
print(ConvertTimeToSeconds("1:00:00:00"))

Don't worry about execution speed before doing any actual measurements unless you're designing a time-critical program. In any extreme situation you'd probably want to offload risky parts to a C module.
Your approach is just fine. There are parts you can clean up: you can just return the results of calculations as TimeInSeconds doesn't actually act as accumulator in your case; tonumber handles '00' just fine and it can ensure decimal integers with an argument (since 5.3).
I'd go the other way and describe factors in a table:
local Factors = {1, 60, 60 * 60, 60 * 60 * 24}
local
function ConvertTimeToSeconds(Time)
local Components = {}
for v in string.gmatch(Time, "%d+") do
table.insert(Components, 1, tonumber(v, 10))
end
if #Components > #Factors then
error("unexpected time component")
end
local TimeInSeconds = 0
for i, v in ipairs(Components) do
TimeInSeconds = TimeInSeconds + v * Factors[i]
end
return TimeInSeconds
end
Of course, both implementations have problem with pattern being naïve as it would match e.g., '00 what 10 ever 10'. To fix that, you could go another route of using string.match with e.g., '(%d+):(%d+):(%d+):(%d+)' and enforcing strict format, or matching each possible variant.
Otherwise you can go all in and use LPeg to parse the duration.
Another way would be to not use strings internally, but instead convert them into a table like {secs=10, mins=1, hours=10, days=1} and then use these tables instead - getting seconds from that representation would be straight-forward.

Related

Changing variable in ode15s [duplicate]

I have a code that uses ode15s to solve. This is my semester question and I am not really good on Matlab but tried to solve the problem like traditional programming way but couldn't achieve success.
The thing I want to achieve is I would like to change the value of Xxc depends on time
Initially Xxc value is 20, but when time will reach 10 then I want to update Xxc to 30 (1.5 times higher) and after that when time is 30 then I want to update Xxc to 40(2.0 times)
There are 2 files
adm1init.m (Initial values)
function ret=adm1init()
global Xxc......
.....
Xxc = 20;
......
time=0:0.2:70;
[t,dX]=ode15s('adm1sys', time, [Ssu Saa Sfa Sva Sbu Spro Sac Sh2 Sch4 SIC SIN SI Xxc Xch Xpr Xli Xsu Xaa Xfa Xc4 Xpro Xac Xh2 XI Scat San Shva Shbu Shpro...
Shac Shco3 Snh3 S_H_ion S_gas_h2 S_gas_ch4 S_gas_co2 q_gas Xhomo XCE Slac Sca]);
ret = dX
These are the only lines that I guess corelated.
Then the calculation file is adm1sys.m
function dX=adm1sys(t,X)
...
rho(1) = k_dis * X(13);
...
rho(13) = k_dec_Xsu * X(17);
rho(14) = k_dec_Xaa * X(18);
rho(15) = k_dec_Xfa * X(19);
rho(16) = k_dec_Xc4 * X(20);
rho(17) = k_dec_Xpro * X(21);
rho(18) = k_dec_Xac * X(22);
rho(19) = k_dec_Xh2 * X(23);
dX(13) = (q_in/V_liq) * (Xxc - X(13)) - rho(1) + sum(rho(13:19));
...
X0(13) = Xxc;
...
I just want to update Xxc value in formula of dX(13) depends on time
if t is 10 just Xxc == 30
if t is 30 just Xxc == 50
But instead of making t >= 10 I just want to apply this patch once.
I can provide other variables depends on formulas if needed.
Thanks

Changing formula in ode15s

I have a code that uses ode15s to solve. This is my semester question and I am not really good on Matlab but tried to solve the problem like traditional programming way but couldn't achieve success.
The thing I want to achieve is I would like to change the value of Xxc depends on time
Initially Xxc value is 20, but when time will reach 10 then I want to update Xxc to 30 (1.5 times higher) and after that when time is 30 then I want to update Xxc to 40(2.0 times)
There are 2 files
adm1init.m (Initial values)
function ret=adm1init()
global Xxc......
.....
Xxc = 20;
......
time=0:0.2:70;
[t,dX]=ode15s('adm1sys', time, [Ssu Saa Sfa Sva Sbu Spro Sac Sh2 Sch4 SIC SIN SI Xxc Xch Xpr Xli Xsu Xaa Xfa Xc4 Xpro Xac Xh2 XI Scat San Shva Shbu Shpro...
Shac Shco3 Snh3 S_H_ion S_gas_h2 S_gas_ch4 S_gas_co2 q_gas Xhomo XCE Slac Sca]);
ret = dX
These are the only lines that I guess corelated.
Then the calculation file is adm1sys.m
function dX=adm1sys(t,X)
...
rho(1) = k_dis * X(13);
...
rho(13) = k_dec_Xsu * X(17);
rho(14) = k_dec_Xaa * X(18);
rho(15) = k_dec_Xfa * X(19);
rho(16) = k_dec_Xc4 * X(20);
rho(17) = k_dec_Xpro * X(21);
rho(18) = k_dec_Xac * X(22);
rho(19) = k_dec_Xh2 * X(23);
dX(13) = (q_in/V_liq) * (Xxc - X(13)) - rho(1) + sum(rho(13:19));
...
X0(13) = Xxc;
...
I just want to update Xxc value in formula of dX(13) depends on time
if t is 10 just Xxc == 30
if t is 30 just Xxc == 50
But instead of making t >= 10 I just want to apply this patch once.
I can provide other variables depends on formulas if needed.
Thanks

Firestore security rules for birthdate

I would like to have a Firestore security rule for bithdate field in my users collections where user age should be >=18 and <=80. I tried the following rule but I know it is not going to work especially for ages that are close to 18 or 80. Any idea how to make this work.
let now = request.time;
let thisYear = now.year();
let thisMonth = now.month();
let thisDay = now.day();
request.resource.data.birthdate >= timestamp.date(thisYear-80,thisMonth,thisDay) &&
request.resource.data.birthdate <= timestamp.date(thisYear-18,thisMonth,thisDay)
You can achieve the same result by comparing it with the request time but in seconds. here’s one example on how this will work:
function isAbove18(date) {
return date.seconds <= request.time.seconds - 18 * 365.25 * 24 * 60 * 60; //considering leap year with 0.25 🙃
}
function isBelow80(date) {
return date.seconds >= request.time.seconds - 80 * 365.25 * 24 * 60 * 60;
}
allow read, write: if isAbove18(resource.data.birthdate) && isBelow80(resource.data.birthdate);
For more about this you can go through this docs which takes some different approaches.

Difference between two date time stamp in Intersystems Cache

I would like to find out the number of hours and minutes between two date time stamp.
if for example
sDateTime = 2016-01-01 01:00
eDateTime = 2016-01-03 02:30
I would like it to output it as 49:30 (49hours and 30minutes)
I am unable to figure a method to work this out.
what I have so far:
Set oMNOF=##class(MNOF.MNOF).%OpenId(Id)
Set zstartDt=oMNOF.sDateTime
Set startDt=$PIECE(zstartDt,",",1)
Set startTime=$PIECE(zstartDt,",",2)
Set zendDt=oMNOF.eDateTime
Set endDt=$PIECE(zendDt,",",1)
Set endTime=$PIECE(zendDt,",",2)
set dateDiff=((endDt - startDt)) //2 days
set timeDiff=(endTime - startTime) //outputs 5400 seconds
set d = (dateDiff * 24 * 60 * 60)
set h = ((timeDiff - d) / 60)
set m = timeDiff - (d) - (h * 60)
Thank you for the help.
Another option:
USER>set mm=$system.SQL.DATEDIFF("mi","2016-01-02 01:00","2016-01-03 02:30")
USER>write "hours=", mm \ 60
hours=25
USER>write "minutes=", mm # 60
minutes=30
Hi thanks to all for the help.
I managed to come up with the below, appreciate if someone can improve on this.
<script language="cache" method="MGetData" arguments="pStartDt:%String,pEndDt:%String,pTimeField:%String" returntype="%Library.String">
set val1="00"
//HOUR: check if length equals 1
if $LENGTH($SYSTEM.SQL.FLOOR($system.SQL.DATEDIFF("ss",pStartDt,pEndDt)/3600))=1{
//add leading zero
set val1 ="0"_$SYSTEM.SQL.FLOOR($system.SQL.DATEDIFF("ss",pStartDt,pEndDt)/3600)
}
else{
//get without leading zero
set val1 = $SYSTEM.SQL.FLOOR($system.SQL.DATEDIFF("ss",pStartDt,pEndDt)/3600)
}
//MINUTES: check if length equals 1
if $LENGTH($SYSTEM.SQL.FLOOR($system.SQL.DATEDIFF("ss",pStartDt,pEndDt)/60) - ($SYSTEM.SQL.FLOOR($system.SQL.DATEDIFF("ss",pStartDt,pEndDt)/3600)*60))=1{
//add leading zero
set val2 ="0"_($SYSTEM.SQL.FLOOR($system.SQL.DATEDIFF("ss",pStartDt,pEndDt)/60) - ($SYSTEM.SQL.FLOOR($system.SQL.DATEDIFF("ss",pStartDt,pEndDt)/3600)*60))
}
else{
//get without leading zero
set val2 = ($SYSTEM.SQL.FLOOR($system.SQL.DATEDIFF("ss",pStartDt,pEndDt)/60) - ($SYSTEM.SQL.FLOOR($system.SQL.DATEDIFF("ss",pStartDt,pEndDt)/3600)*60))
}
//insert result data into the time field
Write "document.getElementById('"_pTimeField_"').value='"_val1_":"_val2_"';"
//Write "alert('"_val1_"^"_val2_"');"
QUIT 1

Compare dates in Lua

I have a variable with a date table that looks like this
* table:
[day]
* number: 15
[year]
* number: 2015
[month]
* number: 2
How do I get the days between the current date and the date above? Many thanks!
You can use os.time() to convert your table to seconds and get the current time and then use os.difftime() to compute the difference. see Lua Wiki for more details.
reference = os.time{day=15, year=2015, month=2}
daysfrom = os.difftime(os.time(), reference) / (24 * 60 * 60) -- seconds in a day
wholedays = math.floor(daysfrom)
print(wholedays) -- today it prints "1"
as #barnes53 pointed out could be off by one day for a few seconds so it's not ideal, but it may be good enough for your needs.
You can use the algorithms gathered here:
chrono-Compatible Low-Level Date Algorithms
The algorithms are shown using C++, but they can be easily implemented in Lua if you like, or you can implement them in C or C++ and then just provide Lua bindings.
The basic idea using these algorithms is to compute a day number for the two dates and then just subtract them to give you the number of days.
--[[
http://howardhinnant.github.io/date_algorithms.html
Returns number of days since civil 1970-01-01. Negative values indicate
days prior to 1970-01-01.
Preconditions: y-m-d represents a date in the civil (Gregorian) calendar
m is in [1, 12]
d is in [1, last_day_of_month(y, m)]
y is "approximately" in
[numeric_limits<Int>::min()/366, numeric_limits<Int>::max()/366]
Exact range of validity is:
[civil_from_days(numeric_limits<Int>::min()),
civil_from_days(numeric_limits<Int>::max()-719468)]
]]
function days_from_civil(y, m, d)
if m <= 2 then
y = y - 1
m = m + 9
else
m = m - 3
end
local era = math.floor(y/400)
local yoe = y - era * 400 -- [0, 399]
local doy = math.modf((153*m + 2)/5) + d-1 -- [0, 365]
local doe = yoe * 365 + math.modf(yoe/4) - math.modf(yoe/100) + doy -- [0, 146096]
return era * 146097 + doe - 719468
end
local reference_date = {year=2001, month = 1, day = 1}
local date = os.date("*t")
local reference_days = days_from_civil(reference_date.year, reference_date.month, reference_date.day)
local days = days_from_civil(date.year, date.month, date.day)
print(string.format("Today is %d days into the 21st century.",days-reference_days))
os.time (under Windows, at least) is limited to years from 1970 and up. If, for example, you need a general solution to also find ages in days for people born before 1970, this won't work. You can use a julian date conversion and subtract between the two numbers (today and your target date).
A sample julian date function that will work for practically any date AD is given below (Lua v5.3 because of // but you could adapt to earlier versions):
local
function div(n,d)
local a, b = 1, 1
if n < 0 then a = -1 end
if d < 0 then b = -1 end
return a * b * (math.abs(n) // math.abs(d))
end
--------------------------------------------------------------------------------
-- Convert a YYMMDD date to Julian since 1/1/1900 (negative answer possible)
--------------------------------------------------------------------------------
function julian(year, month, day)
local temp
if (year < 0) or (month < 1) or (month > 12)
or (day < 1) or (day > 31) then
return
end
temp = div(month - 14, 12)
return (
day - 32075 +
div(1461 * (year + 4800 + temp), 4) +
div(367 * (month - 2 - temp * 12), 12) -
div(3 * div(year + 4900 + temp, 100), 4)
) - 2415021
end