1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
21 ***********************************************************************/
27 * time conversion support
34 #include "FEATURE/tmlib"
37 # if defined(__DYNAMIC__)
38 # define tzname __DYNAMIC__(tzname)
43 # define _dat_tzname 1
44 # define tzname _tzname
49 extern char* tzname
[];
55 static const Namval_t options
[] =
60 "subsecond", TM_SUBSECOND
,
67 * 2007-03-19 move tm_info from _tm_info_ to (*_tm_infop_)
68 * to allow future Tm_info_t growth
69 * by 2009 _tm_info_ can be static
72 #if _BLD_ast && defined(__EXPORT__)
73 #define extern extern __EXPORT__
76 extern Tm_info_t _tm_info_
;
80 Tm_info_t _tm_info_
= { 0 };
82 __EXTERN__(Tm_info_t
, _tm_info_
);
84 __EXTERN__(Tm_info_t
*, _tm_infop_
);
86 Tm_info_t
* _tm_infop_
= &_tm_info_
;
94 _tm_localtime(const time_t* t
)
102 if (!environ
|| !*environ
)
122 * return minutes west of GMT for local time clock
124 * isdst will point to non-zero if DST is in effect
125 * this routine also kicks in the local initialization
129 tzwest(time_t* clock
, int* isdst
)
131 register struct tm
* tp
;
138 * convert to GMT assuming local time
141 if (!(tp
= gmtime(clock
)))
144 * some systems return 0 for negative time_t
156 * tmlocaltime() handles DST and GMT offset
159 tp
= tmlocaltime(clock
);
160 if (n
= tp
->tm_yday
- n
)
167 *isdst
= tp
->tm_isdst
;
168 return (h
- tp
->tm_hour
- n
* 24) * 60 + m
- tp
->tm_min
;
172 * stropt() option handler
176 tmopt(void* a
, const void* p
, int n
, const char* v
)
182 switch (((Namval_t
*)p
)->value
)
185 tm_info
.deformat
= (n
&& (n
= strlen(v
)) > 0 && (n
< 2 || v
[n
-2] != '%' || v
[n
-1] != '?')) ? strdup(v
) : tm_info
.format
[TM_DEFAULT
];
188 tm_info
.local
->type
= (n
&& *v
) ? ((zp
= tmtype(v
, NiL
)) ? zp
->type
: strdup(v
)) : 0;
192 tm_info
.flags
|= ((Namval_t
*)p
)->value
;
194 tm_info
.flags
&= ~((Namval_t
*)p
)->value
;
201 * initialize the local timezone
207 register Tm_zone_t
* zp
;
219 static Tm_zone_t local
;
225 if (s
= getenv("TZ"))
227 sfsprintf(TZ
, sizeof(TZ
), "TZ=%s", s
);
228 if (!environ
|| !*environ
)
251 local
.standard
= strdup(tzname
[0]);
252 local
.daylight
= strdup(tzname
[1]);
260 tm_info
.zone
= tm_info
.local
= &local
;
262 n
= tzwest(&now
, &isdst
);
265 * compute local DST offset by roaming
266 * through the last 12 months until tzwest() changes
269 for (i
= 0; i
< 12; i
++)
271 now
-= 31 * 24 * 60 * 60;
272 if ((m
= tzwest(&now
, &isdst
)) != n
)
288 * now get the time zone names
299 local
.standard
= strdup(tzname
[0]);
301 local
.daylight
= strdup(tzname
[1]);
305 if ((s
= getenv("TZNAME")) && *s
&& (s
= strdup(s
)))
312 if (s
= strchr(s
, ','))
318 else if ((s
= getenv("TZ")) && *s
&& *s
!= ':' && (s
= strdup(s
)))
321 * POSIX style but skipped by tmlocaltime()
325 if (*++s
&& *++s
&& *++s
)
329 for (s
= t
; isalpha(*t
); t
++);
339 * tm_data.zone table lookup
343 for (zp
= tm_data
.zone
; zp
->standard
; zp
++)
347 if (zp
->west
== n
&& zp
->dst
== m
)
350 local
.standard
= zp
->standard
;
351 if (!(s
= zp
->daylight
))
353 e
= (s
= buf
) + sizeof(buf
);
354 s
= tmpoff(s
, e
- s
, zp
->standard
, 0, 0);
358 tmpoff(s
, e
- s
, tm_info
.format
[TM_DT
], m
, TM_DST
);
372 e
= (s
= buf
) + sizeof(buf
);
373 s
= tmpoff(s
, e
- s
, tm_info
.format
[TM_UT
], n
, 0);
374 local
.standard
= strdup(buf
);
378 tmpoff(s
, e
- s
, tm_info
.format
[TM_UT
], m
, TM_DST
);
379 local
.daylight
= strdup(buf
);
388 stropt(getenv("TM_OPTIONS"), options
, sizeof(*options
), tmopt
, NiL
);
391 * the time zone type is probably related to the locale
398 for (zp
= tm_data
.zone
; zp
->standard
; zp
++)
402 if (tmword(s
, NiL
, zp
->standard
, NiL
, 0))
414 if (!(tm_info
.flags
& TM_ADJUST
))
416 now
= (time_t)78811200; /* Jun 30 1972 23:59:60 */
417 tp
= tmlocaltime(&now
);
418 if (tp
->tm_sec
!= 60)
419 tm_info
.flags
|= TM_ADJUST
;
421 if (!(tm_info
.flags
& TM_UTC
))
427 for (; !zp
->type
&& zp
->standard
; zp
++)
428 if (tmword(s
, NiL
, zp
->standard
, NiL
, 0))
430 tm_info
.flags
|= TM_UTC
;
441 tminit(register Tm_zone_t
* zp
)
443 static uint32_t serial
= ~(uint32_t)0;
445 if (serial
!= ast
.env_serial
)
447 serial
= ast
.env_serial
;
450 memset(tm_info
.local
, 0, sizeof(*tm_info
.local
));