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