timezone.inc 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2002 by the Free Pascal development team.
  4. Timezone extraction routines
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. const
  12. TZ_MAGIC = 'TZif';
  13. type
  14. plongint=^longint;
  15. pbyte=^byte;
  16. ttzhead=packed record
  17. tzh_magic : array[0..3] of char;
  18. tzh_reserved : array[1..16] of byte;
  19. tzh_ttisgmtcnt,
  20. tzh_ttisstdcnt,
  21. tzh_leapcnt,
  22. tzh_timecnt,
  23. tzh_typecnt,
  24. tzh_charcnt : longint;
  25. end;
  26. pttinfo=^tttinfo;
  27. tttinfo=packed record
  28. offset : longint;
  29. isdst : boolean;
  30. idx : byte;
  31. isstd : byte;
  32. isgmt : byte;
  33. end;
  34. pleap=^tleap;
  35. tleap=record
  36. transition : longint;
  37. change : longint;
  38. end;
  39. var
  40. num_transitions,
  41. num_leaps,
  42. num_types : longint;
  43. transitions : plongint;
  44. type_idxs : pbyte;
  45. types : pttinfo;
  46. zone_names : pchar;
  47. leaps : pleap;
  48. function find_transition(timer:time_t):pttinfo;
  49. var
  50. i : longint;
  51. begin
  52. if (num_transitions=0) or (timer<time_t(transitions[0])) then
  53. begin
  54. i:=0;
  55. while (i<num_types) and (types[i].isdst) do
  56. inc(i);
  57. if (i=num_types) then
  58. i:=0;
  59. end
  60. else
  61. begin
  62. for i:=1 to num_transitions do
  63. if (timer<transitions[i]) then
  64. break;
  65. i:=type_idxs[i-1];
  66. end;
  67. find_transition:=@types[i];
  68. end;
  69. procedure GetLocalTimezone(timer:time_t;var leap_correct,leap_hit:longint);
  70. var
  71. info : pttinfo;
  72. i : longint;
  73. begin
  74. { reset }
  75. TZDaylight:=false;
  76. TZSeconds:=0;
  77. TZName[false]:=nil;
  78. TZName[true]:=nil;
  79. leap_correct:=0;
  80. leap_hit:=0;
  81. { get info }
  82. info:=find_transition(timer);
  83. if not assigned(info) then
  84. exit;
  85. TZDaylight:=info^.isdst;
  86. TZSeconds:=info^.offset;
  87. i:=0;
  88. while (i<num_types) do
  89. begin
  90. tzname[types[i].isdst]:=@zone_names[types[i].idx];
  91. inc(i);
  92. end;
  93. tzname[info^.isdst]:=@zone_names[info^.idx];
  94. i:=num_leaps;
  95. repeat
  96. if i=0 then
  97. exit;
  98. dec(i);
  99. until (timer>leaps[i].transition);
  100. leap_correct:=leaps[i].change;
  101. if (timer=leaps[i].transition) and
  102. (((i=0) and (leaps[i].change>0)) or
  103. (leaps[i].change>leaps[i-1].change)) then
  104. begin
  105. leap_hit:=1;
  106. while (i>0) and
  107. (leaps[i].transition=leaps[i-1].transition+1) and
  108. (leaps[i].change=leaps[i-1].change+1) do
  109. begin
  110. inc(leap_hit);
  111. dec(i);
  112. end;
  113. end;
  114. end;
  115. procedure GetLocalTimezone(timer:longint);
  116. var
  117. lc,lh : longint;
  118. begin
  119. GetLocalTimezone(timer,lc,lh);
  120. end;
  121. procedure ReadTimezoneFile(fn:string);
  122. procedure decode(var l:longint);
  123. var
  124. k : longint;
  125. p : pbyte;
  126. begin
  127. p:=pbyte(@l);
  128. if (p[0] and (1 shl 7))<>0 then
  129. k:=not 0
  130. else
  131. k:=0;
  132. k:=(k shl 8) or p[0];
  133. k:=(k shl 8) or p[1];
  134. k:=(k shl 8) or p[2];
  135. k:=(k shl 8) or p[3];
  136. l:=k;
  137. end;
  138. var
  139. f : File;
  140. tzdir : string;
  141. tzhead : ttzhead;
  142. i : longint;
  143. chars : longint;
  144. buf : pbyte;
  145. _result : longint;
  146. label lose;
  147. begin
  148. if fn = '' then
  149. exit;
  150. {$IFOPT I+}
  151. {$DEFINE IOCHECK_ON}
  152. {$ENDIF}
  153. {$I-}
  154. Assign(F, fn);
  155. Reset(F,1);
  156. If IOResult <> 0 then
  157. exit;
  158. {$IFDEF IOCHECK_ON}
  159. {$I+}
  160. {$ENDIF}
  161. {$UNDEF IOCHECK_ON}
  162. BlockRead(f,tzhead,sizeof(tzhead),i);
  163. if i<>sizeof(tzhead) then
  164. goto lose;
  165. if tzhead.tzh_magic<>TZ_MAGIC then
  166. begin
  167. goto lose;
  168. end;
  169. decode(tzhead.tzh_timecnt);
  170. decode(tzhead.tzh_typecnt);
  171. decode(tzhead.tzh_charcnt);
  172. decode(tzhead.tzh_leapcnt);
  173. decode(tzhead.tzh_ttisstdcnt);
  174. decode(tzhead.tzh_ttisgmtcnt);
  175. num_transitions:=tzhead.tzh_timecnt;
  176. num_types:=tzhead.tzh_typecnt;
  177. chars:=tzhead.tzh_charcnt;
  178. reallocmem(transitions,num_transitions*sizeof(longint));
  179. reallocmem(type_idxs,num_transitions);
  180. reallocmem(types,num_types*sizeof(tttinfo));
  181. reallocmem(zone_names,chars);
  182. reallocmem(leaps,num_leaps*sizeof(tleap));
  183. BlockRead(f,transitions^,num_transitions*4,_result);
  184. if _result <> num_transitions*4 then
  185. begin
  186. goto lose;
  187. end;
  188. BlockRead(f,type_idxs^,num_transitions,_result);
  189. if _result <> num_transitions then
  190. begin
  191. goto lose;
  192. end;
  193. {* Check for bogus indices in the data file, so we can hereafter
  194. safely use type_idxs[T] as indices into `types' and never crash. *}
  195. for i := 0 to num_transitions-1 do
  196. if (type_idxs[i] >= num_types) then
  197. begin
  198. goto lose;
  199. end;
  200. for i:=0 to num_transitions-1 do
  201. decode(transitions[i]);
  202. for i:=0 to num_types-1 do
  203. begin
  204. blockread(f,types[i].offset,4,_result);
  205. if _result <> 4 then
  206. begin
  207. goto lose;
  208. end;
  209. blockread(f,types[i].isdst,1,_result);
  210. if _result <> 1 then
  211. begin
  212. goto lose;
  213. end;
  214. blockread(f,types[i].idx,1,_result);
  215. if _result <> 1 then
  216. begin
  217. goto lose;
  218. end;
  219. decode(types[i].offset);
  220. types[i].isstd:=0;
  221. types[i].isgmt:=0;
  222. end;
  223. blockread(f,zone_names^,chars,_result);
  224. if _result<>chars then
  225. begin
  226. goto lose;
  227. end;
  228. for i:=0 to num_leaps-1 do
  229. begin
  230. blockread(f,leaps[i].transition,4);
  231. if _result <> 4 then
  232. begin
  233. goto lose;
  234. end;
  235. blockread(f,leaps[i].change,4);
  236. begin
  237. goto lose;
  238. end;
  239. decode(leaps[i].transition);
  240. decode(leaps[i].change);
  241. end;
  242. getmem(buf,tzhead.tzh_ttisstdcnt);
  243. blockread(f,buf^,tzhead.tzh_ttisstdcnt,_result);
  244. if _result<>tzhead.tzh_ttisstdcnt then
  245. begin
  246. goto lose;
  247. end;
  248. for i:=0 to tzhead.tzh_ttisstdcnt-1 do
  249. types[i].isstd:=byte(buf[i]<>0);
  250. freemem(buf);
  251. getmem(buf,tzhead.tzh_ttisgmtcnt);
  252. blockread(f,buf^,tzhead.tzh_ttisgmtcnt);
  253. if _result<>tzhead.tzh_ttisgmtcnt then
  254. begin
  255. goto lose;
  256. end;
  257. for i:=0 to tzhead.tzh_ttisgmtcnt-1 do
  258. types[i].isgmt:=byte(buf[i]<>0);
  259. freemem(buf);
  260. close(f);
  261. exit;
  262. lose:
  263. close(f);
  264. end;
  265. { help function to extract TZ variable data }
  266. function extractnumberend(tzstr: string; offset : integer): integer;
  267. var
  268. j: integer;
  269. begin
  270. j:=0;
  271. extractnumberend := 0;
  272. repeat
  273. if (offset+j) > length(tzstr) then
  274. begin
  275. exit;
  276. end;
  277. inc(j);
  278. until not (tzstr[offset+j] in ['0'..'9']);
  279. extractnumberend := offset+j;
  280. end;
  281. function getoffsetseconds(tzstr: string): longint;
  282. { extract GMT timezone information }
  283. { Returns the number of minutes to }
  284. { add or subtract to the GMT time }
  285. { to get the local time. }
  286. { Format of TZ variable (POSIX) }
  287. { std offset dst }
  288. { std = characters of timezone }
  289. { offset = hh[:mm] to add to GMT }
  290. { dst = daylight savings time }
  291. { CURRENTLY DOES NOT TAKE CARE }
  292. { OF SUMMER TIME DIFFERENCIAL }
  293. var
  294. s: string;
  295. i, j: integer;
  296. code : integer;
  297. hours : longint;
  298. minutes : longint;
  299. negative : boolean;
  300. begin
  301. hours:=0;
  302. minutes:=0;
  303. getoffsetseconds := 0;
  304. negative := FALSE;
  305. i:=-1;
  306. { get to offset field }
  307. repeat
  308. if i > length(tzstr) then
  309. begin
  310. exit;
  311. end;
  312. inc(i);
  313. until (tzstr[i] = '-') or (tzstr[i] in ['0'..'9']);
  314. if tzstr[i] = '-' then
  315. begin
  316. Inc(i);
  317. negative := TRUE;
  318. end;
  319. j:=extractnumberend(tzstr,i);
  320. s:=copy(tzstr,i,j-i);
  321. val(s,hours,code);
  322. if code <> 0 then
  323. begin
  324. exit;
  325. end;
  326. if tzstr[j] = ':' then
  327. begin
  328. i:=j;
  329. Inc(i);
  330. j:=extractnumberend(tzstr,i);
  331. s:=copy(tzstr,i,j-i);
  332. val(s,minutes,code);
  333. if code <> 0 then
  334. begin
  335. exit;
  336. end;
  337. end;
  338. if negative then
  339. begin
  340. minutes := -minutes;
  341. hours := -hours;
  342. end;
  343. getoffsetseconds := minutes*60 + hours*3600;
  344. end;
  345. procedure InitLocalTime;
  346. var
  347. tloc: time_t;
  348. s : string;
  349. begin
  350. TZSeconds:=0;
  351. { try to get the POSIX version }
  352. { of the local time offset }
  353. { if '', then it does not exist }
  354. { if ': ..', then non-POSIX }
  355. s:=GetTimezoneString;
  356. if (s<>'') and (s[1]<>':') then
  357. begin
  358. TZSeconds := getoffsetseconds(s);
  359. end
  360. else
  361. begin
  362. s:=GetTimeZoneFile;
  363. { only read if there is something to read }
  364. if s<>'' then
  365. begin
  366. ReadTimezoneFile(s);
  367. tloc:=sys_time(tloc);
  368. GetLocalTimezone(tloc);
  369. end;
  370. end;
  371. end;
  372. procedure DoneLocalTime;
  373. begin
  374. if assigned(transitions) then
  375. freemem(transitions);
  376. if assigned(type_idxs) then
  377. freemem(type_idxs);
  378. if assigned(types) then
  379. freemem(types);
  380. if assigned(zone_names) then
  381. freemem(zone_names);
  382. if assigned(leaps) then
  383. freemem(leaps);
  384. num_transitions:=0;
  385. num_leaps:=0;
  386. num_types:=0;
  387. end;