Do we have a ready-made (already written) function for translating UTC time into time taking into account TimeZone for Ros 6 ? Probably two functions will be involved here - UnixTime calculations, TimeZone increments and the timeStamp translation function back to “human” time. Thank you.
Concrete example?
Let’s say there is a UTC time and a date of the form 12:00:00 06/07/2023. It is necessary to take into account timeZone (for example Moscow +3.00)
In fact, I need the functions of calculating UnixTime and translating UnixTime to a normal date and time.
ok, generic UTC date-time to unix, add timezone minutes, convert back to date-time…
Rex, do you have the functions ready?
I have such working functions, but I don’t like them, because there is a feeling that they are not quite rationally written. Maybe I’ll post them, and you look?
timeStamp calculation function
limited to 2000-2199 years
without parameters - returns timeStamp (UnixTime)
with $1 parameters - should gmt be taken into account or not
returns the UnixTime of this time point
if $2 is not set, the current date is taken from /system clock
if $3 is not set, the current time is taken in the same way
:global FuncEpochTime do={
:local gmtofset 0
:local ds
:local ts
:if ([:len $1]=0) do={:set gmtofset [/system clock get gmt-offset]} else={:set gmtofset 0}
:if ($1="gmtoffset") do={:set gmtofset [/system clock get gmt-offset]} else={:set gmtofset 0}
:if ($1="nogmt") do={:set gmtofset 0}
:if ([:len $2]=0) do={:set ds [/system clock get date]} else={:set ds $2}
:if ([:len $3]=0) do={:set ts [/system clock get time]} else={:set ts $3}
# :local ds [/system clock get date];
:local months;
:if ((([:pick $ds 9 11]-1)/4) != (([:pick $ds 9 11])/4)) do={
:set months {"an"=0;"eb"=31;"ar"=60;"pr"=91;"ay"=121;"un"=152;"ul"=182;"ug"=213;"ep"=244;"ct"=274;"ov"=305;"ec"=335};
} else={
:set months {"an"=0;"eb"=31;"ar"=59;"pr"=90;"ay"=120;"un"=151;"ul"=181;"ug"=212;"ep"=243;"ct"=273;"ov"=304;"ec"=334};
}
:local year [:tonum [:pick $ds 7 9]]
:set ds (([:pick $ds 9 11]*365)+(([:pick $ds 9 11]-1)/4)+($months->[:pick $ds 1 3])+[:pick $ds 4 6]);
# :local ts [/system clock get time];
:set ts (([:pick $ts 0 2]*60*60)+([:pick $ts 3 5]*60)+[:pick $ts 6 8]);
# :return ($ds*24*60*60 + $ts + 946684800 - $gmtofset);
:if ($year=20) do={
:return ($ds*24*60*60 + $ts + 946684800 - $gmtofset);}
:if ($year=21) do={
:return (($ds-1)*24*60*60 + $ts + 4102444800 - $gmtofset);
} else={:return 0}
}
Step 1, convert date-time 2023/07/06 10:41:07 to unix epoch, assuming the date is on UTC.
This is a modified version of my datetime2epoch that do not consider TimeZone on RouterBOARD, and everytime is supposed the date/time is UTC.
:global UTCdatetime2epoch do={
:local dtime [:tostr $1]
/system clock
:local cyear [get date] ; :if ($cyear ~ "....-..-..") do={:set cyear [:pick $cyear 0 4]} else={:set cyear [:pick $cyear 7 11]}
:if (([:len $dtime] = 10) or ([:len $dtime] = 11)) do={:set dtime "$dtime 00:00:00"}
:if ([:len $dtime] = 15) do={:set dtime "$[:pick $dtime 0 6]/$cyear $[:pick $dtime 7 15]"}
:if ([:len $dtime] = 14) do={:set dtime "$cyear-$[:pick $dtime 0 5] $[:pick $dtime 6 14]"}
:if ([:len $dtime] = 8) do={:set dtime "$[get date] $dtime"}
:if ([:tostr $1] = "") do={:set dtime ("$[get date] $[get time]")}
:local vdate [:pick $dtime 0 [:find $dtime " " -1]]
:local vtime [:pick $dtime ([:find $dtime " " -1] + 1) [:len $dtime]]
:local arrm [:toarray "0,0,31,59,90,120,151,181,212,243,273,304,334"]
:local vdoff [:toarray "0,4,5,7,8,10"]
:local MM [:pick $vdate ($vdoff->2) ($vdoff->3)]
:local M [:tonum $MM]
:if ($vdate ~ ".../../....") do={
:set vdoff [:toarray "7,11,1,3,4,6"]
:set M ([:find "xxanebarprayunulugepctovecANEBARPRAYUNULUGEPCTOVEC" [:pick $vdate ($vdoff->2) ($vdoff->3)] -1] / 2)
:if ($M>12) do={:set M ($M - 12)}
}
:local yyyy [:pick $vdate ($vdoff->0) ($vdoff->1)] ; :if ((($yyyy - 1968) % 4) = 0) do={:set ($arrm->1) -1; :set ($arrm->2) 30}
:local totd ((($yyyy - 1970) * 365) + (($yyyy - 1968) / 4) + ($arrm->$M) + ([:pick $vdate ($vdoff->4) ($vdoff->5)] - 1))
:return (((((($totd * 24) + [:pick $vtime 0 2]) * 60) + [:pick $vtime 3 5]) * 60) + [:pick $vtime 6 8])
}
:put [$UTCdatetime2epoch "2023/07/06 10:41:07"]
1688640067
Step 2, add to unix time the positive or negative value of seconds of timezone.
3h = 10800 seconds
Step 3, convert back the unix to datetime
This is a modified version of my unixtodatetime that do not consider TimeZone on RouterBOARD, and everytime is supposed the unix epoch have already TZ set.
:global NOTZunixtodatetime do={
:local ux [:tonum $1]
:local Fzerofill do={:return [:pick (100 + $1) 1 3]}
:local prMntDays [:toarray "0,0,31,59,90,120,151,181,212,243,273,304,334"]
:local tzepoch ($ux)
:if ($tzepoch < 0) do={:set tzepoch 0} ; # unsupported negative unix epoch
:local yearStart (1970 + ($tzepoch / 31536000))
:local tmpbissex (($yearStart - 1968) / 4) ; :if ((($yearStart - 1968) % 4) = 0) do={:set ($prMntDays->1) -1 ; :set ($prMntDays->2) 30}
:local tmpsec ($tzepoch % 31536000)
:local tmpdays (($tmpsec / 86400) - $tmpbissex)
:if (($tmpsec < (86400 * $tmpbissex)) and ((($yearStart - 1968) % 4) = 0)) do={
:set tmpbissex ($tmpbissex - 1) ; :set ($prMntDays->1) 0 ; :set ($prMntDays->2) 31 ; :set tmpdays ($tmpdays + 1)
}
:if ($tmpsec < (86400 * $tmpbissex)) do={:set yearStart ($yearStart - 1) ; :set tmpdays ($tmpdays + 365)}
:local mnthStart 12 ; :while (($prMntDays->$mnthStart) > $tmpdays) do={:set mnthStart ($mnthStart - 1)}
:local dayStart [$Fzerofill (($tmpdays + 1) - ($prMntDays->$mnthStart))]
:local timeStart (00:00:00 + [:totime ($tmpsec % 86400)])
:return "$yearStart/$[$Fzerofill $mnthStart]/$[$Fzerofill $dayStart] $timeStart"
}
:put [$NOTZunixtodatetime (1688640067 + 10800)]
2023/07/06 13:41:07
The function of translating UnixTime into the usual date and time formats
\
the year is not limited to a century
usial [$FuncUnixTimeToFormat “timeStamp”, “type”]
type:
“unspecified” - month/dd/yyyy ((Mikrotik sheduller format)
1 - yyyy/mm/dd hh:mm:ss
2 - dd:mm:yyyy hh:mm:ss
3 - dd month yyy hh mm ss
4 - yyyy month dd hh mm ss
#5 - month/dd/yyyy-hh:mm:ss (Mikrotik sheduller format)
:global FuncUnixTimeToFormat do={
:local decodedLine ""
:local timeStamp $1
:local timeS ($timeStamp % 86400)
:local timeH ($timeS / 3600)
:local timeM ($timeS % 3600 / 60)
:set $timeS ($timeS - $timeH * 3600 - $timeM * 60)
:local dateD ($timeStamp / 86400)
:local dateM 2
:local dateY 1970
:local leap false
:while (($dateD / 365) > 0) do={
:set $dateD ($dateD - 365)
:set $dateY ($dateY + 1)
:set $dateM ($dateM + 1)
:if ($dateM = 4) do={:set $dateM 0
:if (($dateY % 400 = 0) or ($dateY % 100 != 0)) do={:set $leap true
:set $dateD ($dateD - 1)}} else={:set $leap false}}
:local months [:toarray (0,31,28,31,30,31,30,31,31,30,31,30,31)]
:if (leap) do={:set $dateD ($dateD + 1); :set ($months->2) 29}
do {
:for i from=1 to=12 do={:if (($months->$i) >= $dateD) do={:set $dateM $i; :set $dateD ($dateD + 1); break;} else={:set $dateD ($dateD - ($months->$i))}}
} on-error={}
:local tmod
:if ([:len $2]!=0) do={:set $tmod $2} else={:set $tmod (:nothing)}
:local s "/"
:local nf true
:local mstr {"jan";"feb";"mar";"apr";"may";"jun";"jul";"aug";"sep";"oct";"nov";"dec"}
:local strY [:tostr $dateY]
:local strMn
:local strD
:local strH
:local strM
:local strS
:if ($nf) do={
:if ($dateM > 9) do={:set $strMn [:tostr $dateM]} else={:set $strMn ("0".[:tostr $dateM])}
:if ($dateD > 9) do={:set $strD [:tostr $dateD]} else={:set $strD ("0".[:tostr $dateD])}
:if ($timeH > 9) do={:set $strH [:tostr $timeH]} else={:set $strH ("0".[:tostr $timeH])}
:if ($timeM > 9) do={:set $strM [:tostr $timeM]} else={:set $strM ("0".[:tostr $timeM])}
:if ($timeS > 9) do={:set $strS [:tostr $timeS]} else={:set $strS ("0".[:tostr $timeS])}
} else={
:set strMn [:tostr $dateM]
:set strD [:tostr $dateD]
:set strH [:tostr $timeH]
:set strM [:tostr $timeM]
:set strS [:tostr $timeS]
}
do {
:if ([:len $tmod]=0) do={:local mt ($mstr->($dateM - 1)); :set $decodedLine ("$mt/"."$strD/"."$strY"); break;}
:if ($tmod = 1) do={:set $decodedLine "$strY$s$strMn$s$strD $strH:$strM:$strS"; break;}
:if ($tmod = 2) do={:set $decodedLine "$strD$s$strMn$s$strY $strH:$strM:$strS"; break;}
:if ($tmod = 3) do={:set $decodedLine ("$strD ".($mstr->($dateM - 1))." $strY $strH:$strM:$strS"); break;}
:if ($tmod = 4) do={:set $decodedLine ("$strY ".($mstr->($dateM - 1))." $strD $strH:$strM:$strS"); break;}
:if ($tmod = 5) do={:local m ($mstr->($dateM - 1)); :set $decodedLine ("$m/"."$strD/"."$strY"."-$strH:$strM:$strS"); break;}
} on-error={}
:return $decodedLine;
}
:global FuncEpochTime
:global FuncUnixTimeToFormat
:local nowtime [$FuncEpochTime "nogmt" "Oct/26/2021"]
:log warning [$FuncUnixTimeToFormat $nowtime]
Thank you very much. Within what limits can the timeZone change (from 0 to 24 hours)?
Your wonderful piece of correct gmt-offset calculation
{
:local tzmin [/system clock get gmt-offset]
:if ($tzmin > 0x7FFFFFFF) do={:set tzmin ($tzmin - 0x100000000)}
:local tzsign “+”
:if ($tzmin < 0) do={:set tzsign “-”; :set tzmin ($tzmin * -1)}
:local tzstr [:pick “$tzsign$[:totime $tzmin]” 0 6]
:put “Time Zone offset on this routerboard is $tzstr ($tzsign$tzmin seconds)”
}
Thanks !
Thanks.
The TimeZone corrently go from -14 to +14 hours.
I know it’s absurd the day are 24 hours, not 28… but some states in Oceania, to be the first to celebrate New Year, set the time well ahead of 12 hours…