1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*3e14f97fSRoger A. Faulkner * Copyright (c) 1985-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12da2e3ebdSchin * *
13da2e3ebdSchin * Information and Software Systems Research *
14da2e3ebdSchin * AT&T Research *
15da2e3ebdSchin * Florham Park NJ *
16da2e3ebdSchin * *
17da2e3ebdSchin * Glenn Fowler <gsf@research.att.com> *
18da2e3ebdSchin * David Korn <dgk@research.att.com> *
19da2e3ebdSchin * Phong Vo <kpv@research.att.com> *
20da2e3ebdSchin * *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #pragma prototyped
23da2e3ebdSchin /*
24da2e3ebdSchin * Glenn Fowler
25da2e3ebdSchin * AT&T Research
26da2e3ebdSchin *
27da2e3ebdSchin * time conversion support
28da2e3ebdSchin */
29da2e3ebdSchin
30da2e3ebdSchin #include <tm.h>
31da2e3ebdSchin #include <ctype.h>
32da2e3ebdSchin #include <namval.h>
33da2e3ebdSchin
34da2e3ebdSchin #include "FEATURE/tmlib"
35da2e3ebdSchin
36da2e3ebdSchin #ifndef tzname
37da2e3ebdSchin # if defined(__DYNAMIC__)
38da2e3ebdSchin # define tzname __DYNAMIC__(tzname)
39da2e3ebdSchin # else
40da2e3ebdSchin # if !_dat_tzname
41da2e3ebdSchin # if _dat__tzname
42da2e3ebdSchin # undef _dat_tzname
43da2e3ebdSchin # define _dat_tzname 1
44da2e3ebdSchin # define tzname _tzname
45da2e3ebdSchin # endif
46da2e3ebdSchin # endif
47da2e3ebdSchin # endif
48da2e3ebdSchin # if _dat_tzname
49da2e3ebdSchin extern char* tzname[];
50da2e3ebdSchin # endif
51da2e3ebdSchin #endif
52da2e3ebdSchin
53da2e3ebdSchin #define TM_type (-1)
54da2e3ebdSchin
55da2e3ebdSchin static const Namval_t options[] =
56da2e3ebdSchin {
57da2e3ebdSchin "adjust", TM_ADJUST,
58da2e3ebdSchin "format", TM_DEFAULT,
59da2e3ebdSchin "leap", TM_LEAP,
60da2e3ebdSchin "subsecond", TM_SUBSECOND,
61da2e3ebdSchin "type", TM_type,
62da2e3ebdSchin "utc", TM_UTC,
63da2e3ebdSchin 0, 0
64da2e3ebdSchin };
65da2e3ebdSchin
66da2e3ebdSchin /*
67da2e3ebdSchin * 2007-03-19 move tm_info from _tm_info_ to (*_tm_infop_)
68da2e3ebdSchin * to allow future Tm_info_t growth
69da2e3ebdSchin * by 2009 _tm_info_ can be static
70da2e3ebdSchin */
71da2e3ebdSchin
72da2e3ebdSchin #if _BLD_ast && defined(__EXPORT__)
73da2e3ebdSchin #define extern extern __EXPORT__
74da2e3ebdSchin #endif
75da2e3ebdSchin
76da2e3ebdSchin extern Tm_info_t _tm_info_;
77da2e3ebdSchin
78da2e3ebdSchin #undef extern
79da2e3ebdSchin
80da2e3ebdSchin Tm_info_t _tm_info_ = { 0 };
81da2e3ebdSchin
82da2e3ebdSchin __EXTERN__(Tm_info_t, _tm_info_);
83da2e3ebdSchin
84da2e3ebdSchin __EXTERN__(Tm_info_t*, _tm_infop_);
85da2e3ebdSchin
86da2e3ebdSchin Tm_info_t* _tm_infop_ = &_tm_info_;
87da2e3ebdSchin
88da2e3ebdSchin #if _tzset_environ
89da2e3ebdSchin
90da2e3ebdSchin static char TZ[256];
91da2e3ebdSchin static char* TE[2];
92da2e3ebdSchin
93da2e3ebdSchin struct tm*
_tm_localtime(const time_t * t)94da2e3ebdSchin _tm_localtime(const time_t* t)
95da2e3ebdSchin {
96da2e3ebdSchin struct tm* r;
97da2e3ebdSchin char* e;
98*3e14f97fSRoger A. Faulkner char** v = environ;
99da2e3ebdSchin
100da2e3ebdSchin if (TZ[0])
101da2e3ebdSchin {
102da2e3ebdSchin if (!environ || !*environ)
103da2e3ebdSchin environ = TE;
104da2e3ebdSchin else
105da2e3ebdSchin e = environ[0];
106da2e3ebdSchin environ[0] = TZ;
107da2e3ebdSchin }
108da2e3ebdSchin r = localtime(t);
109da2e3ebdSchin if (TZ[0])
110da2e3ebdSchin {
111*3e14f97fSRoger A. Faulkner if (environ != v)
112*3e14f97fSRoger A. Faulkner environ = v;
113da2e3ebdSchin else
114da2e3ebdSchin environ[0] = e;
115da2e3ebdSchin }
116da2e3ebdSchin return r;
117da2e3ebdSchin }
118da2e3ebdSchin
119da2e3ebdSchin #endif
120da2e3ebdSchin
121da2e3ebdSchin /*
122da2e3ebdSchin * return minutes west of GMT for local time clock
123da2e3ebdSchin *
124da2e3ebdSchin * isdst will point to non-zero if DST is in effect
125da2e3ebdSchin * this routine also kicks in the local initialization
126da2e3ebdSchin */
127da2e3ebdSchin
128da2e3ebdSchin static int
tzwest(time_t * clock,int * isdst)129da2e3ebdSchin tzwest(time_t* clock, int* isdst)
130da2e3ebdSchin {
131da2e3ebdSchin register struct tm* tp;
132da2e3ebdSchin register int n;
133da2e3ebdSchin register int m;
134da2e3ebdSchin int h;
135da2e3ebdSchin time_t epoch;
136da2e3ebdSchin
137da2e3ebdSchin /*
138da2e3ebdSchin * convert to GMT assuming local time
139da2e3ebdSchin */
140da2e3ebdSchin
141da2e3ebdSchin if (!(tp = gmtime(clock)))
142da2e3ebdSchin {
143da2e3ebdSchin /*
144da2e3ebdSchin * some systems return 0 for negative time_t
145da2e3ebdSchin */
146da2e3ebdSchin
147da2e3ebdSchin epoch = 0;
148da2e3ebdSchin clock = &epoch;
149da2e3ebdSchin tp = gmtime(clock);
150da2e3ebdSchin }
151da2e3ebdSchin n = tp->tm_yday;
152da2e3ebdSchin h = tp->tm_hour;
153da2e3ebdSchin m = tp->tm_min;
154da2e3ebdSchin
155da2e3ebdSchin /*
156da2e3ebdSchin * tmlocaltime() handles DST and GMT offset
157da2e3ebdSchin */
158da2e3ebdSchin
159da2e3ebdSchin tp = tmlocaltime(clock);
160da2e3ebdSchin if (n = tp->tm_yday - n)
161da2e3ebdSchin {
162da2e3ebdSchin if (n > 1)
163da2e3ebdSchin n = -1;
164da2e3ebdSchin else if (n < -1)
165da2e3ebdSchin n = 1;
166da2e3ebdSchin }
167da2e3ebdSchin *isdst = tp->tm_isdst;
168da2e3ebdSchin return (h - tp->tm_hour - n * 24) * 60 + m - tp->tm_min;
169da2e3ebdSchin }
170da2e3ebdSchin
171da2e3ebdSchin /*
172da2e3ebdSchin * stropt() option handler
173da2e3ebdSchin */
174da2e3ebdSchin
175da2e3ebdSchin static int
tmopt(void * a,const void * p,int n,const char * v)176da2e3ebdSchin tmopt(void* a, const void* p, int n, const char* v)
177da2e3ebdSchin {
178da2e3ebdSchin Tm_zone_t* zp;
179da2e3ebdSchin
180da2e3ebdSchin NoP(a);
181da2e3ebdSchin if (p)
182da2e3ebdSchin switch (((Namval_t*)p)->value)
183da2e3ebdSchin {
184da2e3ebdSchin case TM_DEFAULT:
185da2e3ebdSchin tm_info.deformat = (n && (n = strlen(v)) > 0 && (n < 2 || v[n-2] != '%' || v[n-1] != '?')) ? strdup(v) : tm_info.format[TM_DEFAULT];
186da2e3ebdSchin break;
187da2e3ebdSchin case TM_type:
188da2e3ebdSchin tm_info.local->type = (n && *v) ? ((zp = tmtype(v, NiL)) ? zp->type : strdup(v)) : 0;
189da2e3ebdSchin break;
190da2e3ebdSchin default:
191da2e3ebdSchin if (n)
192da2e3ebdSchin tm_info.flags |= ((Namval_t*)p)->value;
193da2e3ebdSchin else
194da2e3ebdSchin tm_info.flags &= ~((Namval_t*)p)->value;
195da2e3ebdSchin break;
196da2e3ebdSchin }
197da2e3ebdSchin return 0;
198da2e3ebdSchin }
199da2e3ebdSchin
200da2e3ebdSchin /*
201da2e3ebdSchin * initialize the local timezone
202da2e3ebdSchin */
203da2e3ebdSchin
204da2e3ebdSchin static void
tmlocal(void)205da2e3ebdSchin tmlocal(void)
206da2e3ebdSchin {
207da2e3ebdSchin register Tm_zone_t* zp;
208da2e3ebdSchin register int n;
209da2e3ebdSchin register char* s;
210da2e3ebdSchin register char* e;
211da2e3ebdSchin int i;
212da2e3ebdSchin int m;
213da2e3ebdSchin int isdst;
214da2e3ebdSchin char* t;
215da2e3ebdSchin struct tm* tp;
216da2e3ebdSchin time_t now;
217da2e3ebdSchin char buf[16];
218da2e3ebdSchin
219da2e3ebdSchin static Tm_zone_t local;
220da2e3ebdSchin
221da2e3ebdSchin #if _tzset_environ
222*3e14f97fSRoger A. Faulkner {
223*3e14f97fSRoger A. Faulkner char** v = environ;
224*3e14f97fSRoger A. Faulkner
225da2e3ebdSchin if (s = getenv("TZ"))
226da2e3ebdSchin {
227da2e3ebdSchin sfsprintf(TZ, sizeof(TZ), "TZ=%s", s);
228da2e3ebdSchin if (!environ || !*environ)
229da2e3ebdSchin environ = TE;
230da2e3ebdSchin else
231da2e3ebdSchin e = environ[0];
232da2e3ebdSchin environ[0] = TZ;
233da2e3ebdSchin }
234da2e3ebdSchin else
235da2e3ebdSchin {
236da2e3ebdSchin TZ[0] = 0;
237da2e3ebdSchin e = 0;
238da2e3ebdSchin }
239da2e3ebdSchin #endif
240*3e14f97fSRoger A. Faulkner #if _lib_tzset
241da2e3ebdSchin tzset();
242*3e14f97fSRoger A. Faulkner #endif
243da2e3ebdSchin #if _tzset_environ
244*3e14f97fSRoger A. Faulkner if (environ != v)
245*3e14f97fSRoger A. Faulkner environ = v;
246da2e3ebdSchin else if (e)
247da2e3ebdSchin environ[0] = e;
248*3e14f97fSRoger A. Faulkner }
249da2e3ebdSchin #endif
250da2e3ebdSchin #if _dat_tzname
251da2e3ebdSchin local.standard = strdup(tzname[0]);
252da2e3ebdSchin local.daylight = strdup(tzname[1]);
253da2e3ebdSchin #endif
254da2e3ebdSchin tmlocale();
255da2e3ebdSchin
256da2e3ebdSchin /*
257da2e3ebdSchin * tm_info.local
258da2e3ebdSchin */
259da2e3ebdSchin
260da2e3ebdSchin tm_info.zone = tm_info.local = &local;
261da2e3ebdSchin time(&now);
262da2e3ebdSchin n = tzwest(&now, &isdst);
263da2e3ebdSchin
264da2e3ebdSchin /*
265da2e3ebdSchin * compute local DST offset by roaming
266da2e3ebdSchin * through the last 12 months until tzwest() changes
267da2e3ebdSchin */
268da2e3ebdSchin
269da2e3ebdSchin for (i = 0; i < 12; i++)
270da2e3ebdSchin {
271da2e3ebdSchin now -= 31 * 24 * 60 * 60;
272da2e3ebdSchin if ((m = tzwest(&now, &isdst)) != n)
273da2e3ebdSchin {
274da2e3ebdSchin if (!isdst)
275da2e3ebdSchin {
276da2e3ebdSchin isdst = n;
277da2e3ebdSchin n = m;
278da2e3ebdSchin m = isdst;
279da2e3ebdSchin }
280da2e3ebdSchin m -= n;
281da2e3ebdSchin break;
282da2e3ebdSchin }
283da2e3ebdSchin }
284da2e3ebdSchin local.west = n;
285da2e3ebdSchin local.dst = m;
286da2e3ebdSchin
287da2e3ebdSchin /*
288da2e3ebdSchin * now get the time zone names
289da2e3ebdSchin */
290da2e3ebdSchin
291da2e3ebdSchin #if _dat_tzname
292da2e3ebdSchin if (tzname[0])
293da2e3ebdSchin {
294da2e3ebdSchin /*
295da2e3ebdSchin * POSIX
296da2e3ebdSchin */
297da2e3ebdSchin
298da2e3ebdSchin if (!local.standard)
299da2e3ebdSchin local.standard = strdup(tzname[0]);
300da2e3ebdSchin if (!local.daylight)
301da2e3ebdSchin local.daylight = strdup(tzname[1]);
302da2e3ebdSchin }
303da2e3ebdSchin else
304da2e3ebdSchin #endif
305da2e3ebdSchin if ((s = getenv("TZNAME")) && *s && (s = strdup(s)))
306da2e3ebdSchin {
307da2e3ebdSchin /*
308da2e3ebdSchin * BSD
309da2e3ebdSchin */
310da2e3ebdSchin
311da2e3ebdSchin local.standard = s;
312da2e3ebdSchin if (s = strchr(s, ','))
313da2e3ebdSchin *s++ = 0;
314da2e3ebdSchin else
315da2e3ebdSchin s = "";
316da2e3ebdSchin local.daylight = s;
317da2e3ebdSchin }
318da2e3ebdSchin else if ((s = getenv("TZ")) && *s && *s != ':' && (s = strdup(s)))
319da2e3ebdSchin {
320da2e3ebdSchin /*
321da2e3ebdSchin * POSIX style but skipped by tmlocaltime()
322da2e3ebdSchin */
323da2e3ebdSchin
324da2e3ebdSchin local.standard = s;
325da2e3ebdSchin if (*++s && *++s && *++s)
326da2e3ebdSchin {
327da2e3ebdSchin *s++ = 0;
328da2e3ebdSchin tmgoff(s, &t, 0);
329da2e3ebdSchin for (s = t; isalpha(*t); t++);
330da2e3ebdSchin *t = 0;
331da2e3ebdSchin }
332da2e3ebdSchin else
333da2e3ebdSchin s = "";
334da2e3ebdSchin local.daylight = s;
335da2e3ebdSchin }
336da2e3ebdSchin else
337da2e3ebdSchin {
338da2e3ebdSchin /*
339da2e3ebdSchin * tm_data.zone table lookup
340da2e3ebdSchin */
341da2e3ebdSchin
342da2e3ebdSchin t = 0;
343da2e3ebdSchin for (zp = tm_data.zone; zp->standard; zp++)
344da2e3ebdSchin {
345da2e3ebdSchin if (zp->type)
346da2e3ebdSchin t = zp->type;
347da2e3ebdSchin if (zp->west == n && zp->dst == m)
348da2e3ebdSchin {
349da2e3ebdSchin local.type = t;
350da2e3ebdSchin local.standard = zp->standard;
351da2e3ebdSchin if (!(s = zp->daylight))
352da2e3ebdSchin {
353da2e3ebdSchin e = (s = buf) + sizeof(buf);
354da2e3ebdSchin s = tmpoff(s, e - s, zp->standard, 0, 0);
355da2e3ebdSchin if (s < e - 1)
356da2e3ebdSchin {
357da2e3ebdSchin *s++ = ' ';
358da2e3ebdSchin tmpoff(s, e - s, tm_info.format[TM_DT], m, TM_DST);
359da2e3ebdSchin }
360da2e3ebdSchin s = strdup(buf);
361da2e3ebdSchin }
362da2e3ebdSchin local.daylight = s;
363da2e3ebdSchin break;
364da2e3ebdSchin }
365da2e3ebdSchin }
366da2e3ebdSchin if (!zp->standard)
367da2e3ebdSchin {
368da2e3ebdSchin /*
369da2e3ebdSchin * not in the table
370da2e3ebdSchin */
371da2e3ebdSchin
372da2e3ebdSchin e = (s = buf) + sizeof(buf);
373da2e3ebdSchin s = tmpoff(s, e - s, tm_info.format[TM_UT], n, 0);
374da2e3ebdSchin local.standard = strdup(buf);
375da2e3ebdSchin if (s < e - 1)
376da2e3ebdSchin {
377da2e3ebdSchin *s++ = ' ';
378da2e3ebdSchin tmpoff(s, e - s, tm_info.format[TM_UT], m, TM_DST);
379da2e3ebdSchin local.daylight = strdup(buf);
380da2e3ebdSchin }
381da2e3ebdSchin }
382da2e3ebdSchin }
383da2e3ebdSchin
384da2e3ebdSchin /*
385da2e3ebdSchin * set the options
386da2e3ebdSchin */
387da2e3ebdSchin
388da2e3ebdSchin stropt(getenv("TM_OPTIONS"), options, sizeof(*options), tmopt, NiL);
389da2e3ebdSchin
390da2e3ebdSchin /*
391da2e3ebdSchin * the time zone type is probably related to the locale
392da2e3ebdSchin */
393da2e3ebdSchin
394da2e3ebdSchin if (!local.type)
395da2e3ebdSchin {
396da2e3ebdSchin s = local.standard;
397da2e3ebdSchin t = 0;
398da2e3ebdSchin for (zp = tm_data.zone; zp->standard; zp++)
399da2e3ebdSchin {
400da2e3ebdSchin if (zp->type)
401da2e3ebdSchin t = zp->type;
402da2e3ebdSchin if (tmword(s, NiL, zp->standard, NiL, 0))
403da2e3ebdSchin {
404da2e3ebdSchin local.type = t;
405da2e3ebdSchin break;
406da2e3ebdSchin }
407da2e3ebdSchin }
408da2e3ebdSchin }
409da2e3ebdSchin
410da2e3ebdSchin /*
411da2e3ebdSchin * tm_info.flags
412da2e3ebdSchin */
413da2e3ebdSchin
414da2e3ebdSchin if (!(tm_info.flags & TM_ADJUST))
415da2e3ebdSchin {
416da2e3ebdSchin now = (time_t)78811200; /* Jun 30 1972 23:59:60 */
417da2e3ebdSchin tp = tmlocaltime(&now);
418da2e3ebdSchin if (tp->tm_sec != 60)
419da2e3ebdSchin tm_info.flags |= TM_ADJUST;
420da2e3ebdSchin }
421da2e3ebdSchin if (!(tm_info.flags & TM_UTC))
422da2e3ebdSchin {
423da2e3ebdSchin s = local.standard;
424da2e3ebdSchin zp = tm_data.zone;
425da2e3ebdSchin if (local.daylight)
426da2e3ebdSchin zp++;
427da2e3ebdSchin for (; !zp->type && zp->standard; zp++)
428da2e3ebdSchin if (tmword(s, NiL, zp->standard, NiL, 0))
429da2e3ebdSchin {
430da2e3ebdSchin tm_info.flags |= TM_UTC;
431da2e3ebdSchin break;
432da2e3ebdSchin }
433da2e3ebdSchin }
434da2e3ebdSchin }
435da2e3ebdSchin
436da2e3ebdSchin /*
437da2e3ebdSchin * initialize tm data
438da2e3ebdSchin */
439da2e3ebdSchin
440da2e3ebdSchin void
tminit(register Tm_zone_t * zp)441da2e3ebdSchin tminit(register Tm_zone_t* zp)
442da2e3ebdSchin {
443da2e3ebdSchin static uint32_t serial = ~(uint32_t)0;
444da2e3ebdSchin
445da2e3ebdSchin if (serial != ast.env_serial)
446da2e3ebdSchin {
447da2e3ebdSchin serial = ast.env_serial;
448da2e3ebdSchin if (tm_info.local)
449da2e3ebdSchin {
450da2e3ebdSchin memset(tm_info.local, 0, sizeof(*tm_info.local));
451da2e3ebdSchin tm_info.local = 0;
452da2e3ebdSchin }
453da2e3ebdSchin }
454da2e3ebdSchin if (!tm_info.local)
455da2e3ebdSchin tmlocal();
456da2e3ebdSchin if (!zp)
457da2e3ebdSchin zp = tm_info.local;
458da2e3ebdSchin tm_info.zone = zp;
459da2e3ebdSchin }
460