All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@git.madduck.net.
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
1 local gettime = require "luatz.gettime".gettime
2 local timetable_mt = require "luatz.timetable".timetable_mt
4 local function to_timestamp(o)
5 if type(o) == "number" then
7 elseif getmetatable(o) == timetable_mt then
12 local tz_info_methods = { }
14 __name = "luatz.tz_info";
15 __index = tz_info_methods;
18 __name = "luatz.tt_info";
19 __tostring = function(self)
20 return string.format("tt_info:%s=%d", self.abbr, self.gmtoff)
25 local function find_current(tzinfo, target, i, j)
26 if i >= j then return j end
28 local half = math.ceil((j+i) / 2)
30 if target >= tzinfo[half].transition_time then
31 return find_current(tzinfo, target, half, j)
33 return find_current(tzinfo, target, i, half-1)
37 local function find_current_local(tzinfo, ts_local)
38 -- Find two best possibilities by searching back and forward a day (assumes transition is never by more than 24 hours)
39 local tz_first = find_current(tzinfo, ts_local-86400, 0, #tzinfo)
40 local tz_last = find_current(tzinfo, ts_local+86400, 0, #tzinfo)
42 local n_candidates = tz_last - tz_first + 1
44 if n_candidates == 1 then
46 elseif n_candidates == 2 then
47 local tz_first_ob = tzinfo[tz_first]
48 local tz_last_ob = tzinfo[tz_last]
50 local first_gmtoffset = tz_first_ob.info.gmtoff
51 local last_gmtoffset = tz_last_ob .info.gmtoff
53 local t_start = tz_last_ob.transition_time + first_gmtoffset
54 local t_end = tz_last_ob.transition_time + last_gmtoffset
56 -- If timestamp is before start or after end
57 if ts_local < t_start then
59 elseif ts_local > t_end then
63 -- If we get this far, the local time is ambiguous
64 return tz_first, tz_last
66 error("Too many transitions in a 2 day period")
70 function tz_info_methods:find_current(current)
71 current = assert(to_timestamp(current), "invalid timestamp to :find_current")
72 return self[find_current(self, current, 0, #self)].info
75 function tz_info_methods:localise(utc_ts)
76 utc_ts = utc_ts or gettime()
77 return utc_ts + self:find_current(utc_ts).gmtoff
79 tz_info_methods.localize = tz_info_methods.localise
81 function tz_info_methods:utctime(ts_local)
82 ts_local = assert(to_timestamp(ts_local), "invalid timestamp to :utctime")
83 local tz1, tz2 = find_current_local(self, ts_local)
86 return ts_local - tz1.gmtoff
87 else -- Local time is ambiguous
90 return ts_local - tz2.gmtoff, ts_local - tz2.gmtoff
95 tz_info_mt = tz_info_mt;
96 tt_info_mt = tt_info_mt;