lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


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