timezone.inc 9.0 KB

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