timezone.inc 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. {
  2. Support for timezone info in /usr/share/timezone
  3. }
  4. type
  5. ttzhead=packed record
  6. tzh_reserved : array[0..19] of byte;
  7. tzh_ttisgmtcnt,
  8. tzh_ttisstdcnt,
  9. tzh_leapcnt,
  10. tzh_timecnt,
  11. tzh_typecnt,
  12. tzh_charcnt : longint;
  13. end;
  14. pttinfo=^tttinfo;
  15. tttinfo=packed record
  16. offset : longint;
  17. isdst : boolean;
  18. idx : byte;
  19. isstd : byte;
  20. isgmt : byte;
  21. end;
  22. pleap=^tleap;
  23. tleap=record
  24. transition : longint;
  25. change : longint;
  26. end;
  27. var
  28. num_transitions,
  29. num_leaps,
  30. num_types : longint;
  31. transitions : plongint;
  32. type_idxs : pbyte;
  33. types : pttinfo;
  34. zone_names : pchar;
  35. leaps : pleap;
  36. function find_transition(timer:longint):pttinfo;
  37. var
  38. i : longint;
  39. begin
  40. if (num_transitions=0) or (timer<transitions[0]) then
  41. begin
  42. i:=0;
  43. while (i<num_types) and (types[i].isdst) do
  44. inc(i);
  45. if (i=num_types) then
  46. i:=0;
  47. end
  48. else
  49. begin
  50. for i:=1 to num_transitions do
  51. if (timer<transitions[i]) then
  52. break;
  53. i:=type_idxs[i-1];
  54. end;
  55. find_transition:=@types[i];
  56. end;
  57. procedure GetLocalTimezone(timer:longint;var leap_correct,leap_hit:longint);
  58. var
  59. info : pttinfo;
  60. i : longint;
  61. begin
  62. { reset }
  63. TZDaylight:=false;
  64. TZSeconds:=0;
  65. TZName[false]:=nil;
  66. TZName[true]:=nil;
  67. leap_correct:=0;
  68. leap_hit:=0;
  69. { get info }
  70. info:=find_transition(timer);
  71. if not assigned(info) then
  72. exit;
  73. TZDaylight:=info^.isdst;
  74. TZSeconds:=info^.offset;
  75. i:=0;
  76. while (i<num_types) do
  77. begin
  78. tzname[types[i].isdst]:=@zone_names[types[i].idx];
  79. inc(i);
  80. end;
  81. tzname[info^.isdst]:=@zone_names[info^.idx];
  82. i:=num_leaps;
  83. repeat
  84. if i=0 then
  85. exit;
  86. dec(i);
  87. until (timer>leaps[i].transition);
  88. leap_correct:=leaps[i].change;
  89. if (timer=leaps[i].transition) and
  90. (((i=0) and (leaps[i].change>0)) or
  91. (leaps[i].change>leaps[i-1].change)) then
  92. begin
  93. leap_hit:=1;
  94. while (i>0) and
  95. (leaps[i].transition=leaps[i-1].transition+1) and
  96. (leaps[i].change=leaps[i-1].change+1) do
  97. begin
  98. inc(leap_hit);
  99. dec(i);
  100. end;
  101. end;
  102. end;
  103. procedure GetLocalTimezone(timer:longint);
  104. var
  105. lc,lh : longint;
  106. begin
  107. GetLocalTimezone(timer,lc,lh);
  108. end;
  109. procedure ReadTimezoneFile(fn:shortstring);
  110. procedure decode(var l:longint);
  111. var
  112. k : longint;
  113. p : pbyte;
  114. begin
  115. p:=pbyte(@l);
  116. if (p[0] and (1 shl 7))<>0 then
  117. k:=not 0
  118. else
  119. k:=0;
  120. k:=(k shl 8) or p[0];
  121. k:=(k shl 8) or p[1];
  122. k:=(k shl 8) or p[2];
  123. k:=(k shl 8) or p[3];
  124. l:=k;
  125. end;
  126. const
  127. bufsize = 2048;
  128. var
  129. buf : array[0..bufsize-1] of byte;
  130. bufptr : pbyte;
  131. f : longint;
  132. procedure readfilebuf;
  133. begin
  134. bufptr := @buf[0];
  135. fpread(f, buf, bufsize);
  136. end;
  137. function readbufbyte: byte;
  138. begin
  139. if bufptr > @buf[bufsize-1] then
  140. readfilebuf;
  141. readbufbyte := bufptr^;
  142. inc(bufptr);
  143. end;
  144. function readbuf(var dest; count: integer): integer;
  145. var
  146. numbytes: integer;
  147. begin
  148. readbuf := 0;
  149. repeat
  150. numbytes := (@buf[bufsize-1] + 1) - bufptr;
  151. if numbytes > count then
  152. numbytes := count;
  153. if numbytes > 0 then
  154. begin
  155. move(bufptr^, dest, numbytes);
  156. inc(bufptr, numbytes);
  157. dec(count, numbytes);
  158. inc(readbuf, numbytes);
  159. end;
  160. if count > 0 then
  161. readfilebuf
  162. else
  163. break;
  164. until false;
  165. end;
  166. var
  167. tzdir : shortstring;
  168. tzhead : ttzhead;
  169. i : longint;
  170. chars : longint;
  171. begin
  172. if fn='' then
  173. fn:='localtime';
  174. if fn[1]<>'/' then
  175. begin
  176. tzdir:=fpgetenv('TZDIR');
  177. if tzdir='' then
  178. tzdir:='/usr/share/zoneinfo';
  179. if tzdir[length(tzdir)]<>'/' then
  180. tzdir:=tzdir+'/';
  181. fn:=tzdir+fn;
  182. end;
  183. f:=fpopen(fn,Open_RdOnly);
  184. if f<0 then
  185. exit;
  186. bufptr := @buf[bufsize-1]+1;
  187. i:=readbuf(tzhead,sizeof(tzhead));
  188. if i<>sizeof(tzhead) then
  189. exit;
  190. decode(tzhead.tzh_timecnt);
  191. decode(tzhead.tzh_typecnt);
  192. decode(tzhead.tzh_charcnt);
  193. decode(tzhead.tzh_leapcnt);
  194. decode(tzhead.tzh_ttisstdcnt);
  195. decode(tzhead.tzh_ttisgmtcnt);
  196. num_transitions:=tzhead.tzh_timecnt;
  197. num_types:=tzhead.tzh_typecnt;
  198. chars:=tzhead.tzh_charcnt;
  199. reallocmem(transitions,num_transitions*sizeof(longint));
  200. reallocmem(type_idxs,num_transitions);
  201. reallocmem(types,num_types*sizeof(tttinfo));
  202. reallocmem(zone_names,chars);
  203. reallocmem(leaps,num_leaps*sizeof(tleap));
  204. readbuf(transitions^,num_transitions*4);
  205. readbuf(type_idxs^,num_transitions);
  206. for i:=0 to num_transitions-1 do
  207. decode(transitions[i]);
  208. for i:=0 to num_types-1 do
  209. begin
  210. readbuf(types[i].offset,4);
  211. readbuf(types[i].isdst,1);
  212. readbuf(types[i].idx,1);
  213. decode(types[i].offset);
  214. types[i].isstd:=0;
  215. types[i].isgmt:=0;
  216. end;
  217. readbuf(zone_names^,chars);
  218. for i:=0 to num_leaps-1 do
  219. begin
  220. readbuf(leaps[i].transition,4);
  221. readbuf(leaps[i].change,4);
  222. decode(leaps[i].transition);
  223. decode(leaps[i].change);
  224. end;
  225. for i:=0 to tzhead.tzh_ttisstdcnt-1 do
  226. types[i].isstd:=byte(readbufbyte<>0);
  227. for i:=0 to tzhead.tzh_ttisgmtcnt-1 do
  228. types[i].isgmt:=byte(readbufbyte<>0);
  229. fpclose(f);
  230. end;
  231. Const
  232. // Debian system; contains location of timezone file.
  233. TimeZoneLocationFile = '/etc/timezone';
  234. // SuSE has link in /usr/lib/zoneinfo/localtime to /etc/localtime
  235. // RedHat uses /etc/localtime
  236. TimeZoneFile = '/etc/localtime'; // POSIX
  237. AltTimeZoneFile = '/usr/lib/zoneinfo/localtime'; // Other
  238. iOSTimeZoneFile = '/var/db/timezone/localtime'; // iOS
  239. {$ifdef BSD}
  240. BSDTimeZonefile = '/usr/share/zoneinfo'; // BSD usually is POSIX
  241. // compliant though
  242. {$ENDIF}
  243. {$ifndef FPC_HAS_GETTIMEZONEFILE}
  244. function GetTimezoneFile:shortstring;
  245. var
  246. f,len : longint;
  247. s : shortstring;
  248. info : stat;
  249. begin
  250. GetTimezoneFile:='';
  251. f:=fpopen(TimeZoneLocationFile,Open_RdOnly);
  252. if f>0 then
  253. begin
  254. len:=fpread(f,s[1],high(s));
  255. s[0]:=chr(len);
  256. len:=pos(#10,s);
  257. if len<>0 then
  258. s[0]:=chr(len-1);
  259. fpclose(f);
  260. GetTimezoneFile:=s;
  261. end
  262. // Try SuSE
  263. else if fpstat(TimeZoneFile,{$ifdef oldlinuxstat}baseunix.stat(info){$else}info{$endif})>=0 then
  264. GetTimeZoneFile:=TimeZoneFile
  265. // Try RedHat
  266. else If fpstat(AltTimeZoneFile,{$ifdef oldlinuxstat}baseunix.stat(info){$else}info{$endif})>=0 then
  267. GetTimeZoneFile:=AltTimeZoneFile
  268. {$ifdef BSD}
  269. // else
  270. // If fpstat(BSDTimeZoneFile,{$ifdef oldlinuxstat}baseunix.stat(info){$else}info{$endif})>=0 then
  271. // GetTimeZoneFile:=BSDTimeZoneFile
  272. {$ENDIF}
  273. {$if (defined(darwin) and defined(arm)) or defined(iphonesim)}
  274. else If fpstat(iOSTimeZoneFile,info)>=0 then
  275. GetTimeZoneFile:=iOSTimeZoneFile
  276. {$endif}
  277. end;
  278. {$endif ndef FPC_HAS_GETTIMEZONEFILE}
  279. procedure InitLocalTime;
  280. begin
  281. ReadTimezoneFile(GetTimezoneFile);
  282. GetLocalTimezone(fptime);
  283. end;
  284. procedure DoneLocalTime;
  285. begin
  286. if assigned(transitions) then
  287. freemem(transitions);
  288. if assigned(type_idxs) then
  289. freemem(type_idxs);
  290. if assigned(types) then
  291. freemem(types);
  292. if assigned(zone_names) then
  293. freemem(zone_names);
  294. if assigned(leaps) then
  295. freemem(leaps);
  296. num_transitions:=0;
  297. num_leaps:=0;
  298. num_types:=0;
  299. end;
  300. Procedure ReReadLocalTime;
  301. begin
  302. DoneLocalTime;
  303. InitLocalTime;
  304. end;