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 )
84 tz1 = self [ tz1 ].info
86 return ts_local - tz1.gmtoff
87 else -- Local time is ambiguous
88 tz2 = self [ tz2 ].info
90 return ts_local - tz2.gmtoff , ts_local - tz2.gmtoff
95 tz_info_mt = tz_info_mt ;
96 tt_info_mt = tt_info_mt ;