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