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 tz_info_mt = require "luatz.tzinfo".tz_info_mt
3 local function read_int32be ( fd )
4 local data , err = fd:read ( 4 )
5 if data == nil then return nil , err end
6 local o1 , o2 , o3 , o4 = data:byte ( 1 , 4 )
8 local unsigned = o4 + o3*2^8 + o2*2^16 + o1*2^24
9 if unsigned >= 2^31 then
10 return unsigned - 2^32
16 local function read_int64be ( fd )
17 local data , err = fd:read ( 8 )
18 if data == nil then return nil , err end
19 local o1 , o2 , o3 , o4 , o5 , o6 , o7 , o8 = data:byte ( 1 , 8 )
21 local unsigned = o8 + o7*2^8 + o6*2^16 + o5*2^24 + o4*2^32 + o3*2^40 + o2*2^48 + o1*2^56
22 if unsigned >= 2^63 then
23 return unsigned - 2^64
29 local function read_flags ( fd , n )
30 local data , err = fd:read ( n )
31 if data == nil then return nil , err end
35 res[i] = data:byte(i,i) ~= 0
40 local fifteen_nulls = ("\0"):rep(15)
41 local function read_tz ( fd )
42 assert ( fd:read(4) == "TZif" )
43 local version = assert ( fd:read(1) )
44 if version == "\0" or version == "2" then
45 local MIN_TIME = -2^32+1
47 assert ( assert ( fd:read(15) ) == fifteen_nulls , "Expected 15 nulls" )
49 -- The number of UTC/local indicators stored in the file.
50 local tzh_ttisgmtcnt = assert ( read_int32be ( fd ) )
52 -- The number of standard/wall indicators stored in the file.
53 local tzh_ttisstdcnt = assert ( read_int32be ( fd ) )
55 -- The number of leap seconds for which data is stored in the file.
56 local tzh_leapcnt = assert ( read_int32be ( fd ) )
58 -- The number of "transition times" for which data is stored in the file.
59 local tzh_timecnt = assert ( read_int32be ( fd ) )
61 -- The number of "local time types" for which data is stored in the file (must not be zero).
62 local tzh_typecnt = assert ( read_int32be ( fd ) )
64 -- The number of characters of "timezone abbreviation strings" stored in the file.
65 local tzh_charcnt = assert ( read_int32be ( fd ) )
67 local transition_times = { }
68 for i=1, tzh_timecnt do
69 transition_times [ i ] = assert ( read_int32be ( fd ) )
71 local transition_time_ind = { assert ( fd:read ( tzh_timecnt ) ):byte ( 1 , -1 ) }
74 for i=1, tzh_typecnt do
76 gmtoff = assert ( read_int32be ( fd ) ) ;
77 isdst = assert ( fd:read ( 1 ) ) ~= "\0" ;
78 abbrind = assert ( fd:read ( 1 ) ):byte ( ) ;
82 local abbreviations = assert ( fd:read ( tzh_charcnt ) )
84 local leap_seconds = { }
85 for i=1, tzh_leapcnt do
86 leap_seconds [ i ] = {
87 offset = assert ( read_int32be ( fd ) ) ;
88 n = assert ( read_int32be ( fd ) ) ;
92 local isstd = assert ( read_flags ( fd , tzh_ttisstdcnt ) )
94 local isgmt = assert ( read_flags ( fd , tzh_ttisgmtcnt ) )
96 if version == "2" then
98 For version-2-format timezone files, the above header and data is followed by a second header and data,
99 identical in format except that eight bytes are used for each transition time or leap-second time.
101 assert ( fd:read(5) == "TZif2" )
102 assert ( assert ( fd:read(15) ) == fifteen_nulls , "Expected 15 nulls" )
106 -- The number of UTC/local indicators stored in the file.
107 tzh_ttisgmtcnt = assert ( read_int32be ( fd ) )
109 -- The number of standard/wall indicators stored in the file.
110 tzh_ttisstdcnt = assert ( read_int32be ( fd ) )
112 -- The number of leap seconds for which data is stored in the file.
113 tzh_leapcnt = assert ( read_int32be ( fd ) )
115 -- The number of "transition times" for which data is stored in the file.
116 tzh_timecnt = assert ( read_int32be ( fd ) )
118 -- The number of "local time types" for which data is stored in the file (must not be zero).
119 tzh_typecnt = assert ( read_int32be ( fd ) )
121 -- The number of characters of "timezone abbreviation strings" stored in the file.
122 tzh_charcnt = assert ( read_int32be ( fd ) )
124 transition_times = { }
125 for i=1, tzh_timecnt do
126 transition_times [ i ] = assert ( read_int64be ( fd ) )
128 transition_time_ind = { assert ( fd:read ( tzh_timecnt ) ):byte ( 1 , -1 ) }
131 for i=1, tzh_typecnt do
133 gmtoff = assert ( read_int32be ( fd ) ) ;
134 isdst = assert ( fd:read ( 1 ) ) ~= "\0" ;
135 abbrind = assert ( fd:read ( 1 ) ):byte ( ) ;
139 abbreviations = assert ( fd:read ( tzh_charcnt ) )
142 for i=1, tzh_leapcnt do
143 leap_seconds [ i ] = {
144 offset = assert ( read_int64be ( fd ) ) ;
145 n = assert ( read_int32be ( fd ) ) ;
149 isstd = assert ( read_flags ( fd , tzh_ttisstdcnt ) )
151 isgmt = assert ( read_flags ( fd , tzh_ttisgmtcnt ) )
154 After the second header and data comes a newline-enclosed, POSIX-TZ-environment-variable-style string
155 for use in handling instants after the last transition time stored in the file
156 (with nothing between the newlines if there is no POSIX representation for such instants).
160 for i=1, tzh_typecnt do
161 local v = ttinfos [ i ]
162 v.abbr = abbreviations:sub ( v.abbrind+1 , v.abbrind+3 )
163 v.isstd = isstd [ i ] or false
164 v.isgmt = isgmt [ i ] or false
168 Use the first standard-time ttinfo structure in the file
169 (or simply the first ttinfo structure in the absence of a standard-time structure)
170 if either tzh_timecnt is zero or the time argument is less than the first transition time recorded in the file.
174 for i=1, tzh_ttisstdcnt do
184 transition_time = MIN_TIME ;
185 info = ttinfos [ first ] ;
188 for i=1, tzh_timecnt do
190 transition_time = transition_times [ i ] ;
191 info = ttinfos [ transition_time_ind [ i ]+1 ] ;
194 return setmetatable ( res , tz_info_mt )
196 error ( "Unsupported version" )
200 local function read_tzfile ( path )
201 local fd = assert ( io.open ( path ) )
202 local tzinfo = read_tz ( fd )
209 read_tzfile = read_tzfile ;