|
local ffi = require('ffi') |
|
local clock = require('clock') |
|
local builtin = ffi.C |
|
|
|
local datetime_t = ffi.typeof('struct datetime') |
|
local SECS_PER_DAY = 86400 |
|
local DT_EPOCH_1970_OFFSET = 719163LL |
|
|
|
ffi.cdef [[ |
|
struct datetime_double { |
|
/** seconds since epoch */ |
|
double secs; |
|
/** nanoseconds if any */ |
|
int32_t nsec; |
|
/** offset in minutes from UTC */ |
|
int32_t offset; |
|
}; |
|
|
|
]] |
|
|
|
local datetime_double_t = ffi.typeof('struct datetime_double') |
|
|
|
local function datetime_new_raw(secs, nsec, offset) |
|
local dt_obj = ffi.new(datetime_t) |
|
dt_obj.secs = secs |
|
dt_obj.nsec = nsec |
|
dt_obj.offset = offset |
|
return dt_obj |
|
end |
|
|
|
|
|
local function datetime_new_raw_2(secs, nsec, offset) |
|
local dt_obj = ffi.new(datetime_double_t) |
|
dt_obj.secs = secs |
|
dt_obj.nsec = nsec |
|
dt_obj.offset = offset |
|
return dt_obj |
|
end |
|
|
|
local function datetime_index(self, key) |
|
if key == 'epoch' or key == 'unixtime' then |
|
return self.secs |
|
elseif key == 'secsf' then |
|
return builtin.datetime_secs(self) |
|
elseif key == 'ts' or key == 'timestamp' then |
|
return tonumber(self.secs) + self.nsec / 1e9 |
|
elseif key == 'ns' or key == 'nanoseconds' then |
|
return self.secs * 1e9 + self.nsec |
|
elseif key == 'us' or key == 'microseconds' then |
|
return self.secs * 1e6 + self.nsec / 1e3 |
|
elseif key == 'ms' or key == 'milliseconds' then |
|
return self.secs * 1e3 + self.nsec / 1e6 |
|
elseif key == 's' or key == 'seconds' then |
|
return tonumber(self.secs) + self.nsec / 1e9 |
|
elseif key == 'm' or key == 'min' or key == 'minutes' then |
|
return (tonumber(self.secs) + self.nsec / 1e9) / 60 |
|
elseif key == 'hr' or key == 'hours' then |
|
return (tonumber(self.secs) + self.nsec / 1e9) / (60 * 60) |
|
elseif key == 'd' or key == 'days' then |
|
return (tonumber(self.secs) + self.nsec / 1e9) / (24 * 60 * 60) |
|
else |
|
error(('unknown attribute %s'):format(key), 2) |
|
end |
|
end |
|
|
|
local function datetime_newindex(self, key, value) |
|
if key == 'epoch' or key == 'unixtime' then |
|
self.secs = value |
|
self.nsec, self.offset = 0, 0 |
|
else |
|
error(('assigning to unknown attribute %s'):format(key), 2) |
|
end |
|
end |
|
|
|
local datetime_mt = { |
|
__index = datetime_index, |
|
__newindex = datetime_newindex, |
|
} |
|
|
|
-- ffi.metatype(datetime_t, datetime_mt) |
|
|
|
|
|
local _ |
|
local T |
|
|
|
T = datetime_new_raw(60, 100000, 180) |
|
print(ffi.typeof(T)) |
|
|
|
local start = clock.time() |
|
for _ = 1, 1e6 do |
|
_ = T.secs |
|
end |
|
print('date.secs', clock.time() - start) |
|
|
|
collectgarbage() |
|
collectgarbage() |
|
print(ffi.typeof(T)) |
|
|
|
start = clock.time() |
|
for _ = 1, 1e6 do |
|
_ = T.secsf |
|
end |
|
print('date.secsf', clock.time() - start) |
|
collectgarbage() |
|
collectgarbage() |
|
|
|
local N = datetime_new_raw_2(60, 100000, 180) |
|
print(ffi.typeof(N)) |
|
|
|
start = clock.time() |
|
for _ = 1, 1e6 do |
|
_ = N.secs |
|
end |
|
print('date_double.secs', clock.time() - start) |