• Subject: Re: Back and forth UTC dates
• From: Francisco Olarte <folarte@...>
• Date: Tue, 28 Mar 2017 15:30:46 +0200

```Javier:

On Tue, Mar 28, 2017 at 12:32 PM, Javier Mr <javiersdevmail@ymail.com> wrote:
> I'm having a little bit of trouble converting dates in UTC to timestamps and back to dates.

Having some time to play I've done a lua version of my perl code. It's
not too fast, as I wanted clarity, but the 10M round trips can be done
in 19.3 seconds on an old Xeon, so it should suffice.

For the test I just passed it through luacheck and after it made it
generate a bunch of random values between the epoch and something in
the near future and round trip them through os.date and the function.
A better test would test some extreme values and a better function
should make some checking / defaulting / normalization on parameters,
but I'm quite confident the algorithm is correct and can serve as a
starting point.

So, code after signature.

Happy hacking.
Francisco Olarte.

-- Small sample to convert an utc table from os.date into a timestamp
again.

-- Days before the 1st of each month.
local days_before={0}

-- Note I do not need december.
for m,d in ipairs{31,28,31,30,31,30,31,31,30,31,30} do
days_before[m+1]=days_before[m]+d
end

-- We will fill it later.
local epoch_days = 0

local function days_since_epoch(y,m,d)
local leap_years = y//4 - y//100 + y//100
-- Using 0 or 1 based days, month or years does not matter as
-- months are just used to index days_before and epoch_days
updating
-- below takes care of extra offset.
local days = d + days_before[m] + y*365 + leap_years
local is_leap_year = (y%4==0) and ( y%100~=0 or y%400==0)
if is_leap_year and m<3 then
-- We added one leap year to many before, substract it.
return days-1-epoch_days
else
return days-epoch_days
end
end

-- Dirty trick, set epoch_days to correct value
epoch_days = days_since_epoch(1970,1,1)

-- Everything in place, now we can do:
local function utc_parts_to_ts(y,m,d,h,mi,s)
return s+60*(mi+60*(h+24*days_since_epoch(y,m,d)))
end

-- More things to do, but this should do for an example.
local function utc_time(t)
if t then
return utc_parts_to_ts(t.year, t.month, t.day, t.hour, t.min, t.sec)
else
return os.time()
end
end

-- Test it a bit, extreme values would be better but I'm lazy.
local upper = os.time()+10000000
for _=1,10000000 do
local ts1 = math.random(upper)
local utc_date = os.date("!*t", ts1)
local ts2 = utc_time(utc_date)
if (ts1~=ts2) then
print ("Error:",ts1,ts2)
end
end

```