]> git.madduck.net Git - etc/awesome.git/blob - luatz/tzinfo.lua

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

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.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

luatz/tzinfo: Give tt_info objects a __tostring
[etc/awesome.git] / luatz / tzinfo.lua
1 local gettime = require "luatz.gettime".gettime
2
3 local tz_info_methods = { }
4 local tz_info_mt = {
5         __index = tz_info_methods ;
6 }
7 local tt_info_mt = {
8         __tostring = function ( self )
9                 return string.format ( "tt_info:%s=%d" , self.abbr , self.gmtoff )
10         end ;
11 }
12
13 -- Binary search
14 local function _find_current ( tzinfo , target , i , j )
15         if i >= j then return j end
16
17         local half = math.ceil ( (j+i) / 2 )
18
19         if target >= tzinfo [ half ].transition_time then
20                 return _find_current ( tzinfo , target , half , j )
21         else
22                 return _find_current ( tzinfo , target , i , half-1 )
23         end
24 end
25
26 local function find_current_local ( tzinfo , ts_local )
27         -- Find two best possibilities by searching back and forward a day (assumes transition is never by more than 24 hours)
28         local tz_first = _find_current ( tzinfo , ts_local-86400 , 0 , #tzinfo )
29         local tz_last  = _find_current ( tzinfo , ts_local+86400 , 0 , #tzinfo )
30
31         local n_candidates = tz_last - tz_first + 1
32
33         if n_candidates == 1 then
34                 return tz_first
35         elseif n_candidates == 2 then
36                 local tz_first_ob = tzinfo [ tz_first ]
37                 local tz_last_ob  = tzinfo [ tz_last ]
38
39                 local first_gmtoffset = tz_first_ob.info.gmtoff
40                 local last_gmtoffset  = tz_last_ob .info.gmtoff
41
42                 local t_start = tz_last_ob.transition_time + first_gmtoffset
43                 local t_end   = tz_last_ob.transition_time + last_gmtoffset
44
45                 -- If timestamp is before start or after end
46                 if ts_local < t_start then
47                         return tz_first
48                 elseif ts_local > t_end then
49                         return tz_last
50                 end
51
52                 -- If we get this far, the local time is ambiguous
53                 return tz_first , tz_last
54         else
55                 error ( "Too many transitions in a 2 day period" )
56         end
57 end
58
59 function tz_info_methods:find_current ( current )
60         return self [ _find_current ( self , current , 0 , #self ) ].info
61 end
62
63 function tz_info_methods:localise ( utc_ts )
64         utc_ts = utc_ts or gettime ( )
65         return utc_ts + self:find_current ( utc_ts ).gmtoff
66 end
67 tz_info_methods.localize = tz_info_methods.localise
68
69 function tz_info_methods:utctime ( ts_local )
70         local tz1 , tz2 = find_current_local ( self , ts_local )
71         tz1 = self [ tz1 ].info
72         if tz2 == nil then
73                 return ts_local - tz1.gmtoff
74         else -- Local time is ambiguous
75                 tz2 = self [ tz2 ].info
76
77                 return ts_local - tz2.gmtoff , ts_local - tz2.gmtoff
78         end
79 end
80
81 return {
82         tz_info_mt = tz_info_mt ;
83         tt_info_mt = tt_info_mt ;
84 }