make Local channel return sensible device state values
[asterisk-bristuff.git] / stdtime / localtime.c
blob5be8a14f2ff53165b49b3b71e6d367674ae16d64
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * Most of this code is in the public domain, so clarified as of
9 * June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov).
11 * All modifications to this code to abstract timezones away from
12 * the environment are by Tilghman Lesher, <tlesher@vcch.com>, with
13 * the copyright assigned to Digium.
15 * See http://www.asterisk.org for more information about
16 * the Asterisk project. Please do not directly contact
17 * any of the maintainers of this project for assistance;
18 * the project provides a web site, mailing lists and IRC
19 * channels for your use.
21 * This program is free software, distributed under the terms of
22 * the GNU General Public License Version 2. See the LICENSE file
23 * at the top of the source tree.
26 /*! \file
28 * Multi-timezone Localtime code
30 * \author Leap second handling Bradley White (bww@k.gp.cs.cmu.edu).
31 * \author POSIX-style TZ environment variable handling from Guy Harris (guy@auspex.com).
36 * Asterisk defines
38 * Don't mess with these unless you're really sure you know what you're doing.
40 #ifndef _THREAD_SAFE
41 #define _THREAD_SAFE
42 #endif
43 #define TZ_STRLEN_MAX 255
44 /* #define DEBUG */
46 #include "asterisk.h"
48 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
50 /*LINTLIBRARY*/
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include <fcntl.h>
55 #ifdef DEBUG
56 #include <stdio.h>
57 #endif
59 #include "private.h"
60 #include "tzfile.h"
61 #include "asterisk/lock.h"
62 #include "asterisk/localtime.h"
65 #ifndef lint
66 #ifndef NOID
67 static const char elsieid[] = "@(#)localtime.c 7.57";
68 #endif /* !defined NOID */
69 #endif /* !defined lint */
74 ** SunOS 4.1.1 headers lack O_BINARY.
77 #ifdef O_BINARY
78 #define OPEN_MODE (O_RDONLY | O_BINARY)
79 #endif /* defined O_BINARY */
80 #ifndef O_BINARY
81 #define OPEN_MODE O_RDONLY
82 #endif /* !defined O_BINARY */
84 #ifdef SOLARIS
85 #undef TM_ZONE
86 #undef TM_GMTOFF
87 #endif
89 #ifdef TM_ZONE
90 #ifndef WILDABBR
91 /*! \note
92 * Someone might make incorrect use of a time zone abbreviation:
93 * 1. They might reference tzname[0] before calling ast_tzset (explicitly
94 * or implicitly).
95 * 2. They might reference tzname[1] before calling ast_tzset (explicitly
96 * or implicitly).
97 * 3. They might reference tzname[1] after setting to a time zone
98 * in which Daylight Saving Time is never observed.
99 * 4. They might reference tzname[0] after setting to a time zone
100 * in which Standard Time is never observed.
101 * 5. They might reference tm.TM_ZONE after calling offtime.
102 * What's best to do in the above cases is open to debate;
103 * for now, we just set things up so that in any of the five cases
104 * WILDABBR is used. Another possibility: initialize tzname[0] to the
105 * string "tzname[0] used before set", and similarly for the other cases.
106 * And another: initialize tzname[0] to "ERA", with an explanation in the
107 * manual page of what this "time zone abbreviation" means (doing this so
108 * that tzname[0] has the "normal" length of three characters).
110 #define WILDABBR " "
111 #endif /* !defined WILDABBR */
113 static char wildabbr[] = "WILDABBR";
114 #endif /* TM_ZONE */
116 /*! \brief FreeBSD defines 'zone' in 'struct tm' as non-const, so don't declare this
117 string as const. */
118 static char gmt[] = "GMT";
120 /*!< \brief time type information */
121 struct ttinfo {
122 long tt_gmtoff; /*!< GMT offset in seconds */
123 int tt_isdst; /*!< used to set tm_isdst */
124 int tt_abbrind; /*!< abbreviation list index */
125 int tt_ttisstd; /*!< TRUE if transition is std time */
126 int tt_ttisgmt; /*!< TRUE if transition is GMT */
129 /*! \brief leap second information */
130 struct lsinfo {
131 time_t ls_trans; /*!< transition time */
132 long ls_corr; /*!< correction to apply */
135 #define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
137 #ifdef TZNAME_MAX
138 #define MY_TZNAME_MAX TZNAME_MAX
139 #endif /* defined TZNAME_MAX */
140 #ifndef TZNAME_MAX
141 #define MY_TZNAME_MAX 255
142 #endif /* !defined TZNAME_MAX */
144 struct state {
145 char name[TZ_STRLEN_MAX + 1];
146 int leapcnt;
147 int timecnt;
148 int typecnt;
149 int charcnt;
150 time_t ats[TZ_MAX_TIMES];
151 unsigned char types[TZ_MAX_TIMES];
152 struct ttinfo ttis[TZ_MAX_TYPES];
153 char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
154 (2 * (MY_TZNAME_MAX + 1)))];
155 struct lsinfo lsis[TZ_MAX_LEAPS];
156 struct state *next;
159 struct rule {
160 int r_type; /*!< type of rule--see below */
161 int r_day; /*!< day number of rule */
162 int r_week; /*!< week number of rule */
163 int r_mon; /*!< month number of rule */
164 long r_time; /*!< transition time of rule */
167 #define JULIAN_DAY 0 /*!< Jn - Julian day */
168 #define DAY_OF_YEAR 1 /*!< n - day of year */
169 #define MONTH_NTH_DAY_OF_WEEK 2 /*!< Mm.n.d - month, week, day of week */
172 ** Prototypes for static functions.
175 static long detzcode P((const char * codep));
176 static const char * getnum P((const char * strp, int * nump, int min,
177 int max));
178 static const char * getsecs P((const char * strp, long * secsp));
179 static const char * getoffset P((const char * strp, long * offsetp));
180 static const char * getrule P((const char * strp, struct rule * rulep));
181 static void gmtload P((struct state * sp));
182 static void gmtsub P((const time_t * timep, long offset,
183 struct tm * tmp, const char * zone));
184 static void localsub P((const time_t * timep, long offset,
185 struct tm * tmp, const char * zone));
186 static int increment_overflow P((int * number, int delta));
187 static int normalize_overflow P((int * tensptr, int * unitsptr,
188 int base));
189 static time_t time1 P((struct tm * tmp,
190 void(*funcp) P((const time_t *,
191 long, struct tm *, const char*)),
192 long offset, const char * zone));
193 static time_t time2 P((struct tm *tmp,
194 void(*funcp) P((const time_t *,
195 long, struct tm*, const char*)),
196 long offset, int * okayp, const char * zone));
197 static void timesub P((const time_t * timep, long offset,
198 const struct state * sp, struct tm * tmp));
199 static int tmcomp P((const struct tm * atmp,
200 const struct tm * btmp));
201 static time_t transtime P((time_t janfirst, int year,
202 const struct rule * rulep, long offset));
203 static int tzload P((const char * name, struct state * sp));
204 static int tzparse P((const char * name, struct state * sp,
205 int lastditch));
207 static struct state * lclptr = NULL;
208 static struct state * last_lclptr = NULL;
209 static struct state * gmtptr = NULL;
211 #ifndef TZ_STRLEN_MAX
212 #define TZ_STRLEN_MAX 255
213 #endif /* !defined TZ_STRLEN_MAX */
215 static int gmt_is_set;
216 #ifdef _THREAD_SAFE
217 AST_MUTEX_DEFINE_STATIC(lcl_mutex);
218 AST_MUTEX_DEFINE_STATIC(tzset_mutex);
219 AST_MUTEX_DEFINE_STATIC(tzsetwall_mutex);
220 AST_MUTEX_DEFINE_STATIC(gmt_mutex);
221 #endif
224 ** Section 4.12.3 of X3.159-1989 requires that
225 ** Except for the strftime function, these functions [asctime,
226 ** ctime, gmtime, localtime] return values in one of two static
227 ** objects: a broken-down time structure and an array of char.
228 ** Thanks to Paul Eggert (eggert@twinsun.com) for noting this.
231 static long detzcode(const char * const codep)
233 register long result;
234 register int i;
236 result = (codep[0] & 0x80) ? ~0L : 0L;
237 for (i = 0; i < 4; ++i)
238 result = (result << 8) | (codep[i] & 0xff);
239 return result;
242 static int tzload(register const char *name, register struct state *const sp)
244 register const char * p;
245 register int i;
246 register int fid;
248 #ifdef DEBUG
249 fprintf(stderr,"tzload called with name=%s, sp=%d\n", name, sp);
250 #endif
251 if (name == NULL && (name = TZDEFAULT) == NULL)
252 return -1;
254 register int doaccess;
255 struct stat stab;
257 ** Section 4.9.1 of the C standard says that
258 ** "FILENAME_MAX expands to an integral constant expression
259 ** that is the size needed for an array of char large enough
260 ** to hold the longest file name string that the implementation
261 ** guarantees can be opened."
263 char fullname[FILENAME_MAX + 1] = "";
265 if (name[0] == ':')
266 ++name;
267 doaccess = name[0] == '/';
268 if (!doaccess) {
269 if ((p = TZDIR) == NULL)
270 return -1;
271 if ((strlen(p) + 1 + strlen(name) + 1) >= sizeof fullname)
272 return -1;
273 (void) strncpy(fullname, p, sizeof(fullname) - 1);
274 (void) strncat(fullname, "/", sizeof(fullname) - strlen(fullname) - 1);
275 (void) strncat(fullname, name, sizeof(fullname) - strlen(fullname) - 1);
277 ** Set doaccess if '.' (as in "../") shows up in name.
279 if (strchr(name, '.') != NULL)
280 doaccess = TRUE;
281 name = fullname;
283 if (doaccess && access(name, R_OK) != 0)
284 return -1;
285 if ((fid = open(name, OPEN_MODE)) == -1)
286 return -1;
287 if ((fstat(fid, &stab) < 0) || !S_ISREG(stab.st_mode)) {
288 close(fid);
289 return -1;
293 struct tzhead * tzhp;
294 char buf[sizeof *sp + sizeof *tzhp];
295 int ttisstdcnt;
296 int ttisgmtcnt;
298 i = read(fid, buf, sizeof buf);
299 if (close(fid) != 0)
300 return -1;
301 p = buf;
302 p += (sizeof tzhp->tzh_magic) + (sizeof tzhp->tzh_reserved);
303 ttisstdcnt = (int) detzcode(p);
304 p += 4;
305 ttisgmtcnt = (int) detzcode(p);
306 p += 4;
307 sp->leapcnt = (int) detzcode(p);
308 p += 4;
309 sp->timecnt = (int) detzcode(p);
310 p += 4;
311 sp->typecnt = (int) detzcode(p);
312 p += 4;
313 sp->charcnt = (int) detzcode(p);
314 p += 4;
315 if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
316 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
317 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
318 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
319 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
320 (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
321 return -1;
322 if (i - (p - buf) < sp->timecnt * 4 + /* ats */
323 sp->timecnt + /* types */
324 sp->typecnt * (4 + 2) + /* ttinfos */
325 sp->charcnt + /* chars */
326 sp->leapcnt * (4 + 4) + /* lsinfos */
327 ttisstdcnt + /* ttisstds */
328 ttisgmtcnt) /* ttisgmts */
329 return -1;
330 for (i = 0; i < sp->timecnt; ++i) {
331 sp->ats[i] = detzcode(p);
332 p += 4;
334 for (i = 0; i < sp->timecnt; ++i) {
335 sp->types[i] = (unsigned char) *p++;
336 if (sp->types[i] >= sp->typecnt)
337 return -1;
339 for (i = 0; i < sp->typecnt; ++i) {
340 register struct ttinfo * ttisp;
342 ttisp = &sp->ttis[i];
343 ttisp->tt_gmtoff = detzcode(p);
344 p += 4;
345 ttisp->tt_isdst = (unsigned char) *p++;
346 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
347 return -1;
348 ttisp->tt_abbrind = (unsigned char) *p++;
349 if (ttisp->tt_abbrind < 0 ||
350 ttisp->tt_abbrind > sp->charcnt)
351 return -1;
353 for (i = 0; i < sp->charcnt; ++i)
354 sp->chars[i] = *p++;
355 sp->chars[i] = '\0'; /* ensure '\0' at end */
356 for (i = 0; i < sp->leapcnt; ++i) {
357 register struct lsinfo * lsisp;
359 lsisp = &sp->lsis[i];
360 lsisp->ls_trans = detzcode(p);
361 p += 4;
362 lsisp->ls_corr = detzcode(p);
363 p += 4;
365 for (i = 0; i < sp->typecnt; ++i) {
366 register struct ttinfo * ttisp;
368 ttisp = &sp->ttis[i];
369 if (ttisstdcnt == 0)
370 ttisp->tt_ttisstd = FALSE;
371 else {
372 ttisp->tt_ttisstd = *p++;
373 if (ttisp->tt_ttisstd != TRUE &&
374 ttisp->tt_ttisstd != FALSE)
375 return -1;
378 for (i = 0; i < sp->typecnt; ++i) {
379 register struct ttinfo * ttisp;
381 ttisp = &sp->ttis[i];
382 if (ttisgmtcnt == 0)
383 ttisp->tt_ttisgmt = FALSE;
384 else {
385 ttisp->tt_ttisgmt = *p++;
386 if (ttisp->tt_ttisgmt != TRUE &&
387 ttisp->tt_ttisgmt != FALSE)
388 return -1;
392 return 0;
395 static const int mon_lengths[2][MONSPERYEAR] = {
396 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
397 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
400 static const int year_lengths[2] = {
401 DAYSPERNYEAR, DAYSPERLYEAR
404 /*! \brief
405 * Given a pointer into a time zone string, extract a number from that string.
406 * \return Check that the number is within a specified range; if it is not, return
407 * NULL.
408 * Otherwise, return a pointer to the first character not part of the number.
411 static const char *getnum(register const char *strp, int * const nump, const int min, const int max)
413 register char c;
414 register int num;
416 if (strp == NULL || !is_digit(c = *strp))
417 return NULL;
418 num = 0;
419 do {
420 num = num * 10 + (c - '0');
421 if (num > max)
422 return NULL; /* illegal value */
423 c = *++strp;
424 } while (is_digit(c));
425 if (num < min)
426 return NULL; /* illegal value */
427 *nump = num;
428 return strp;
431 /*! \brief
432 * Given a pointer into a time zone string, extract a number of seconds,
433 * in hh[:mm[:ss]] form, from the string.
434 * \return If any error occurs, return NULL.
435 * Otherwise, return a pointer to the first character not part of the number
436 * of seconds.
439 static const char *getsecs(register const char *strp, long * const secsp)
441 int num;
444 ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
445 ** "M10.4.6/26", which does not conform to Posix,
446 ** but which specifies the equivalent of
447 ** ``02:00 on the first Sunday on or after 23 Oct''.
449 strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
450 if (strp == NULL)
451 return NULL;
452 *secsp = num * (long) SECSPERHOUR;
453 if (*strp == ':') {
454 ++strp;
455 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
456 if (strp == NULL)
457 return NULL;
458 *secsp += num * SECSPERMIN;
459 if (*strp == ':') {
460 ++strp;
461 /* `SECSPERMIN' allows for leap seconds. */
462 strp = getnum(strp, &num, 0, SECSPERMIN);
463 if (strp == NULL)
464 return NULL;
465 *secsp += num;
468 return strp;
471 /*! \brief
472 * Given a pointer into a time zone string, extract an offset, in
473 * [+-]hh[:mm[:ss]] form, from the string.
474 * \return If any error occurs, return NULL.
475 * Otherwise, return a pointer to the first character not part of the time.
478 static const char * getoffset(register const char *strp, long * const offsetp)
480 register int neg = 0;
482 if (*strp == '-') {
483 neg = 1;
484 ++strp;
485 } else if (*strp == '+')
486 ++strp;
487 strp = getsecs(strp, offsetp);
488 if (strp == NULL)
489 return NULL; /* illegal time */
490 if (neg)
491 *offsetp = -*offsetp;
492 return strp;
495 /*! \brief
496 * Given a pointer into a time zone string, extract a rule in the form
497 * date[/time]. See POSIX section 8 for the format of "date" and "time".
498 * \return If a valid rule is not found, return NULL.
499 * Otherwise, return a pointer to the first character not part of the rule.
502 static const char *getrule(const char *strp, register struct rule * const rulep)
504 if (*strp == 'J') {
506 ** Julian day.
508 rulep->r_type = JULIAN_DAY;
509 ++strp;
510 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
511 } else if (*strp == 'M') {
513 ** Month, week, day.
515 rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
516 ++strp;
517 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
518 if (strp == NULL)
519 return NULL;
520 if (*strp++ != '.')
521 return NULL;
522 strp = getnum(strp, &rulep->r_week, 1, 5);
523 if (strp == NULL)
524 return NULL;
525 if (*strp++ != '.')
526 return NULL;
527 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
528 } else if (is_digit(*strp)) {
530 ** Day of year.
532 rulep->r_type = DAY_OF_YEAR;
533 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
534 } else return NULL; /* invalid format */
535 if (strp == NULL)
536 return NULL;
537 if (*strp == '/') {
539 ** Time specified.
541 ++strp;
542 strp = getsecs(strp, &rulep->r_time);
543 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
544 return strp;
547 /*! \brief
548 * Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
549 * year, a rule, and the offset from GMT at the time that rule takes effect,
550 * calculate the Epoch-relative time that rule takes effect.
553 static time_t transtime(janfirst, year, rulep, offset)
554 const time_t janfirst;
555 const int year;
556 register const struct rule * const rulep;
557 const long offset;
559 register int leapyear;
560 register time_t value = 0;
561 register int i;
562 int d, m1, yy0, yy1, yy2, dow;
564 leapyear = isleap(year);
565 switch (rulep->r_type) {
567 case JULIAN_DAY:
569 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
570 ** years.
571 ** In non-leap years, or if the day number is 59 or less, just
572 ** add SECSPERDAY times the day number-1 to the time of
573 ** January 1, midnight, to get the day.
575 value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
576 if (leapyear && rulep->r_day >= 60)
577 value += SECSPERDAY;
578 break;
580 case DAY_OF_YEAR:
582 ** n - day of year.
583 ** Just add SECSPERDAY times the day number to the time of
584 ** January 1, midnight, to get the day.
586 value = janfirst + rulep->r_day * SECSPERDAY;
587 break;
589 case MONTH_NTH_DAY_OF_WEEK:
591 ** Mm.n.d - nth "dth day" of month m.
593 value = janfirst;
594 for (i = 0; i < rulep->r_mon - 1; ++i)
595 value += mon_lengths[leapyear][i] * SECSPERDAY;
598 ** Use Zeller's Congruence to get day-of-week of first day of
599 ** month.
601 m1 = (rulep->r_mon + 9) % 12 + 1;
602 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
603 yy1 = yy0 / 100;
604 yy2 = yy0 % 100;
605 dow = ((26 * m1 - 2) / 10 +
606 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
607 if (dow < 0)
608 dow += DAYSPERWEEK;
611 ** "dow" is the day-of-week of the first day of the month. Get
612 ** the day-of-month (zero-origin) of the first "dow" day of the
613 ** month.
615 d = rulep->r_day - dow;
616 if (d < 0)
617 d += DAYSPERWEEK;
618 for (i = 1; i < rulep->r_week; ++i) {
619 if (d + DAYSPERWEEK >=
620 mon_lengths[leapyear][rulep->r_mon - 1])
621 break;
622 d += DAYSPERWEEK;
626 ** "d" is the day-of-month (zero-origin) of the day we want.
628 value += d * SECSPERDAY;
629 break;
633 ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
634 ** question. To get the Epoch-relative time of the specified local
635 ** time on that day, add the transition time and the current offset
636 ** from GMT.
638 return value + rulep->r_time + offset;
642 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
643 ** appropriate.
646 static int
647 tzparse(name, sp, lastditch)
648 const char * name;
649 register struct state * const sp;
650 const int lastditch;
652 const char * stdname;
653 const char * dstname = NULL;
654 size_t stdlen = 0;
655 size_t dstlen = 0;
656 long stdoffset = 0L;
657 long dstoffset = 0L;
658 register time_t * atp;
659 register unsigned char * typep;
660 register char * cp;
661 register int load_result;
663 stdname = name;
664 #ifdef DEBUG
665 fprintf(stderr, "tzparse(): loading default rules\n");
666 #endif
667 load_result = tzload(TZDEFRULES, sp);
668 if (load_result != 0)
669 sp->leapcnt = 0; /* so, we're off a little */
670 if (*name != '\0') {
671 if (*name != '\0' && *name != ',' && *name != ';') {
672 name = getoffset(name, &dstoffset);
673 if (name == NULL)
674 return -1;
675 } else dstoffset = stdoffset - SECSPERHOUR;
676 if (*name == ',' || *name == ';') {
677 struct rule start;
678 struct rule end;
679 register int year;
680 register time_t janfirst;
681 time_t starttime;
682 time_t endtime;
684 ++name;
685 if ((name = getrule(name, &start)) == NULL)
686 return -1;
687 if (*name++ != ',')
688 return -1;
689 if ((name = getrule(name, &end)) == NULL)
690 return -1;
691 if (*name != '\0')
692 return -1;
693 sp->typecnt = 2; /* standard time and DST */
695 ** Two transitions per year, from EPOCH_YEAR to 2037.
697 sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
698 if (sp->timecnt > TZ_MAX_TIMES)
699 return -1;
700 sp->ttis[0].tt_gmtoff = -dstoffset;
701 sp->ttis[0].tt_isdst = 1;
702 sp->ttis[0].tt_abbrind = stdlen + 1;
703 sp->ttis[1].tt_gmtoff = -stdoffset;
704 sp->ttis[1].tt_isdst = 0;
705 sp->ttis[1].tt_abbrind = 0;
706 atp = sp->ats;
707 typep = sp->types;
708 janfirst = 0;
709 for (year = EPOCH_YEAR; year <= 2037; ++year) {
710 starttime = transtime(janfirst, year, &start,
711 stdoffset);
712 endtime = transtime(janfirst, year, &end,
713 dstoffset);
714 if (starttime > endtime) {
715 *atp++ = endtime;
716 *typep++ = 1; /* DST ends */
717 *atp++ = starttime;
718 *typep++ = 0; /* DST begins */
719 } else {
720 *atp++ = starttime;
721 *typep++ = 0; /* DST begins */
722 *atp++ = endtime;
723 *typep++ = 1; /* DST ends */
725 janfirst += year_lengths[isleap(year)] *
726 SECSPERDAY;
728 } else {
729 register long theirstdoffset;
730 register long theirdstoffset;
731 register long theiroffset;
732 register int isdst;
733 register int i;
734 register int j;
736 if (*name != '\0')
737 return -1;
738 if (load_result != 0)
739 return -1;
741 ** Initial values of theirstdoffset and theirdstoffset.
743 theirstdoffset = 0;
744 for (i = 0; i < sp->timecnt; ++i) {
745 j = sp->types[i];
746 if (!sp->ttis[j].tt_isdst) {
747 theirstdoffset =
748 -sp->ttis[j].tt_gmtoff;
749 break;
752 theirdstoffset = 0;
753 for (i = 0; i < sp->timecnt; ++i) {
754 j = sp->types[i];
755 if (sp->ttis[j].tt_isdst) {
756 theirdstoffset =
757 -sp->ttis[j].tt_gmtoff;
758 break;
762 ** Initially we're assumed to be in standard time.
764 isdst = FALSE;
765 theiroffset = theirstdoffset;
767 ** Now juggle transition times and types
768 ** tracking offsets as you do.
770 for (i = 0; i < sp->timecnt; ++i) {
771 j = sp->types[i];
772 sp->types[i] = sp->ttis[j].tt_isdst;
773 if (sp->ttis[j].tt_ttisgmt) {
774 /* No adjustment to transition time */
775 } else {
777 ** If summer time is in effect, and the
778 ** transition time was not specified as
779 ** standard time, add the summer time
780 ** offset to the transition time;
781 ** otherwise, add the standard time
782 ** offset to the transition time.
785 ** Transitions from DST to DDST
786 ** will effectively disappear since
787 ** POSIX provides for only one DST
788 ** offset.
790 if (isdst && !sp->ttis[j].tt_ttisstd) {
791 sp->ats[i] += dstoffset -
792 theirdstoffset;
793 } else {
794 sp->ats[i] += stdoffset -
795 theirstdoffset;
798 theiroffset = -sp->ttis[j].tt_gmtoff;
799 if (sp->ttis[j].tt_isdst)
800 theirdstoffset = theiroffset;
801 else theirstdoffset = theiroffset;
804 ** Finally, fill in ttis.
805 ** ttisstd and ttisgmt need not be handled.
807 sp->ttis[0].tt_gmtoff = -stdoffset;
808 sp->ttis[0].tt_isdst = FALSE;
809 sp->ttis[0].tt_abbrind = 0;
810 sp->ttis[1].tt_gmtoff = -dstoffset;
811 sp->ttis[1].tt_isdst = TRUE;
812 sp->ttis[1].tt_abbrind = stdlen + 1;
814 } else {
815 dstlen = 0;
816 sp->typecnt = 1; /* only standard time */
817 sp->timecnt = 0;
818 sp->ttis[0].tt_gmtoff = -stdoffset;
819 sp->ttis[0].tt_isdst = 0;
820 sp->ttis[0].tt_abbrind = 0;
822 sp->charcnt = stdlen + 1;
823 if (dstlen != 0)
824 sp->charcnt += dstlen + 1;
825 if (sp->charcnt > sizeof sp->chars)
826 return -1;
827 cp = sp->chars;
828 (void) strncpy(cp, stdname, stdlen);
829 cp += stdlen;
830 *cp++ = '\0';
831 if (dstlen != 0) {
832 (void) strncpy(cp, dstname, dstlen);
833 *(cp + dstlen) = '\0';
835 return 0;
838 static void
839 gmtload(sp)
840 struct state * const sp;
842 if (tzload(gmt, sp) != 0)
843 (void) tzparse(gmt, sp, TRUE);
847 ** A non-static declaration of ast_tzsetwall in a system header file
848 ** may cause a warning about this upcoming static declaration...
850 static
851 #ifdef _THREAD_SAFE
853 ast_tzsetwall_basic P((void))
854 #else
856 ast_tzsetwall P((void))
857 #endif
859 struct state *cur_state = lclptr;
861 /* Find the appropriate structure, if already parsed */
862 while (cur_state != NULL) {
863 if (cur_state->name[0] == '\0')
864 break;
865 cur_state = cur_state->next;
867 if (cur_state != NULL)
868 return 0;
869 cur_state = malloc(sizeof(struct state));
870 if (cur_state == NULL) {
871 return -1;
873 memset(cur_state,0,sizeof(struct state));
874 if (tzload((char *) NULL, cur_state) != 0)
875 #ifdef DEBUG
877 fprintf(stderr, "ast_tzsetwall: calling gmtload()\n");
878 #endif
879 gmtload(cur_state);
880 #ifdef DEBUG
882 #endif
884 if (last_lclptr)
885 last_lclptr->next = cur_state;
886 else
887 lclptr = cur_state;
888 last_lclptr = cur_state;
889 return 0;
892 #ifdef _THREAD_SAFE
894 ast_tzsetwall P((void))
896 ast_mutex_lock(&tzsetwall_mutex);
897 ast_tzsetwall_basic();
898 ast_mutex_unlock(&tzsetwall_mutex);
899 return 0;
901 #endif
903 #ifdef _THREAD_SAFE
904 static int
905 ast_tzset_basic P((const char *name))
906 #else
908 ast_tzset P((const char *name))
909 #endif
911 struct state *cur_state = lclptr;
913 /* Not set at all */
914 if (name == NULL) {
915 return ast_tzsetwall();
918 /* Find the appropriate structure, if already parsed */
919 while (cur_state != NULL) {
920 if (!strcmp(cur_state->name,name))
921 break;
922 cur_state = cur_state->next;
924 if (cur_state != NULL)
925 return 0;
927 cur_state = malloc(sizeof(struct state));
928 if (cur_state == NULL) {
929 return -1;
931 memset(cur_state,0,sizeof(*cur_state));
933 /* Name is set, but set to the empty string == no adjustments */
934 if (name[0] == '\0') {
936 ** User wants it fast rather than right.
938 cur_state->leapcnt = 0; /* so, we're off a little */
939 cur_state->timecnt = 0;
940 cur_state->ttis[0].tt_gmtoff = 0;
941 cur_state->ttis[0].tt_abbrind = 0;
942 (void) strncpy(cur_state->chars, gmt, sizeof(cur_state->chars) - 1);
943 } else if (tzload(name, cur_state) != 0) {
944 if (name[0] == ':') {
945 (void) gmtload(cur_state);
946 } else if (tzparse(name, cur_state, FALSE) != 0) {
947 /* If not found, load localtime */
948 if (tzload("/etc/localtime", cur_state) != 0)
949 /* Last ditch, get GMT */
950 (void) gmtload(cur_state);
953 strncpy(cur_state->name, name, sizeof(cur_state->name) - 1);
954 if (last_lclptr)
955 last_lclptr->next = cur_state;
956 else
957 lclptr = cur_state;
958 last_lclptr = cur_state;
959 return 0;
962 #ifdef _THREAD_SAFE
963 void
964 ast_tzset P((const char *name))
966 ast_mutex_lock(&tzset_mutex);
967 ast_tzset_basic(name);
968 ast_mutex_unlock(&tzset_mutex);
970 #endif
973 ** The easy way to behave "as if no library function calls" localtime
974 ** is to not call it--so we drop its guts into "localsub", which can be
975 ** freely called. (And no, the PANS doesn't require the above behavior--
976 ** but it *is* desirable.)
978 ** The unused offset argument is for the benefit of mktime variants.
981 /*ARGSUSED*/
982 static void
983 localsub(timep, offset, tmp, zone)
984 const time_t * const timep;
985 const long offset;
986 struct tm * const tmp;
987 const char * const zone;
989 register struct state * sp;
990 register const struct ttinfo * ttisp;
991 register int i;
992 const time_t t = *timep;
994 sp = lclptr;
995 /* Find the right zone record */
996 if (zone == NULL)
997 sp = NULL;
998 else
999 while (sp != NULL) {
1000 if (!strcmp(sp->name,zone))
1001 break;
1002 sp = sp->next;
1005 if (sp == NULL) {
1006 ast_tzsetwall();
1007 sp = lclptr;
1008 /* Find the default zone record */
1009 while (sp != NULL) {
1010 if (sp->name[0] == '\0')
1011 break;
1012 sp = sp->next;
1016 /* Last ditch effort, use GMT */
1017 if (sp == NULL) {
1018 gmtsub(timep, offset, tmp, zone);
1019 return;
1021 if (sp->timecnt == 0 || t < sp->ats[0]) {
1022 i = 0;
1023 while (sp->ttis[i].tt_isdst)
1024 if (++i >= sp->typecnt) {
1025 i = 0;
1026 break;
1028 } else {
1029 for (i = 1; i < sp->timecnt; ++i)
1030 if (t < sp->ats[i])
1031 break;
1032 i = sp->types[i - 1];
1034 ttisp = &sp->ttis[i];
1036 ** To get (wrong) behavior that's compatible with System V Release 2.0
1037 ** you'd replace the statement below with
1038 ** t += ttisp->tt_gmtoff;
1039 ** timesub(&t, 0L, sp, tmp);
1041 timesub(&t, ttisp->tt_gmtoff, sp, tmp);
1042 tmp->tm_isdst = ttisp->tt_isdst;
1043 tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
1044 #ifdef TM_ZONE
1045 tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
1046 #endif /* defined TM_ZONE */
1049 struct tm *
1050 ast_localtime(timep, p_tm, zone)
1051 const time_t * const timep;
1052 struct tm *p_tm;
1053 const char * const zone;
1055 #ifdef _THREAD_SAFE
1056 ast_mutex_lock(&lcl_mutex);
1057 #endif
1058 ast_tzset(zone);
1059 localsub(timep, 0L, p_tm, zone);
1060 #ifdef _THREAD_SAFE
1061 ast_mutex_unlock(&lcl_mutex);
1062 #endif
1063 return(p_tm);
1067 ** gmtsub is to gmtime as localsub is to localtime.
1070 static void
1071 gmtsub(timep, offset, tmp, zone)
1072 const time_t * const timep;
1073 const long offset;
1074 struct tm * const tmp;
1075 const char * const zone;
1077 #ifdef _THREAD_SAFE
1078 ast_mutex_lock(&gmt_mutex);
1079 #endif
1080 if (!gmt_is_set) {
1081 gmt_is_set = TRUE;
1082 gmtptr = (struct state *) malloc(sizeof *gmtptr);
1083 if (gmtptr != NULL)
1084 gmtload(gmtptr);
1086 ast_mutex_unlock(&gmt_mutex);
1087 timesub(timep, offset, gmtptr, tmp);
1088 #ifdef TM_ZONE
1090 ** Could get fancy here and deliver something such as
1091 ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
1092 ** but this is no time for a treasure hunt.
1094 if (offset != 0)
1095 tmp->TM_ZONE = wildabbr;
1096 else {
1097 if (gmtptr == NULL)
1098 tmp->TM_ZONE = gmt;
1099 else tmp->TM_ZONE = gmtptr->chars;
1101 #endif /* defined TM_ZONE */
1104 static void
1105 timesub(timep, offset, sp, tmp)
1106 const time_t * const timep;
1107 const long offset;
1108 register const struct state * const sp;
1109 register struct tm * const tmp;
1111 register const struct lsinfo * lp;
1112 register long days;
1113 register long rem;
1114 register int y;
1115 register int yleap;
1116 register const int * ip;
1117 register long corr;
1118 register int hit;
1119 register int i;
1121 corr = 0;
1122 hit = 0;
1123 i = (sp == NULL) ? 0 : sp->leapcnt;
1124 while (--i >= 0) {
1125 lp = &sp->lsis[i];
1126 if (*timep >= lp->ls_trans) {
1127 if (*timep == lp->ls_trans) {
1128 hit = ((i == 0 && lp->ls_corr > 0) ||
1129 lp->ls_corr > sp->lsis[i - 1].ls_corr);
1130 if (hit)
1131 while (i > 0 &&
1132 sp->lsis[i].ls_trans ==
1133 sp->lsis[i - 1].ls_trans + 1 &&
1134 sp->lsis[i].ls_corr ==
1135 sp->lsis[i - 1].ls_corr + 1) {
1136 ++hit;
1137 --i;
1140 corr = lp->ls_corr;
1141 break;
1144 days = *timep / SECSPERDAY;
1145 rem = *timep % SECSPERDAY;
1146 #ifdef mc68k
1147 if (*timep == 0x80000000) {
1149 ** A 3B1 muffs the division on the most negative number.
1151 days = -24855;
1152 rem = -11648;
1154 #endif /* defined mc68k */
1155 rem += (offset - corr);
1156 while (rem < 0) {
1157 rem += SECSPERDAY;
1158 --days;
1160 while (rem >= SECSPERDAY) {
1161 rem -= SECSPERDAY;
1162 ++days;
1164 tmp->tm_hour = (int) (rem / SECSPERHOUR);
1165 rem = rem % SECSPERHOUR;
1166 tmp->tm_min = (int) (rem / SECSPERMIN);
1168 ** A positive leap second requires a special
1169 ** representation. This uses "... ??:59:60" et seq.
1171 tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
1172 tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
1173 if (tmp->tm_wday < 0)
1174 tmp->tm_wday += DAYSPERWEEK;
1175 y = EPOCH_YEAR;
1176 #define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
1177 while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
1178 register int newy;
1180 newy = y + days / DAYSPERNYEAR;
1181 if (days < 0)
1182 --newy;
1183 days -= (newy - y) * DAYSPERNYEAR +
1184 LEAPS_THRU_END_OF(newy - 1) -
1185 LEAPS_THRU_END_OF(y - 1);
1186 y = newy;
1188 tmp->tm_year = y - TM_YEAR_BASE;
1189 tmp->tm_yday = (int) days;
1190 ip = mon_lengths[yleap];
1191 for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
1192 days = days - (long) ip[tmp->tm_mon];
1193 tmp->tm_mday = (int) (days + 1);
1194 tmp->tm_isdst = 0;
1195 #ifdef TM_GMTOFF
1196 tmp->TM_GMTOFF = offset;
1197 #endif /* defined TM_GMTOFF */
1200 char *
1201 ast_ctime(timep)
1202 const time_t * const timep;
1205 ** Section 4.12.3.2 of X3.159-1989 requires that
1206 ** The ctime funciton converts the calendar time pointed to by timer
1207 ** to local time in the form of a string. It is equivalent to
1208 ** asctime(localtime(timer))
1210 return asctime(localtime(timep));
1213 char *
1214 ast_ctime_r(timep, buf)
1215 const time_t * const timep;
1216 char *buf;
1218 struct tm tm;
1219 #ifdef SOLARIS
1220 return asctime_r(localtime_r(timep, &tm), buf, 256);
1221 #else
1222 return asctime_r(localtime_r(timep, &tm), buf);
1223 #endif
1227 ** Adapted from code provided by Robert Elz, who writes:
1228 ** The "best" way to do mktime I think is based on an idea of Bob
1229 ** Kridle's (so its said...) from a long time ago.
1230 ** [kridle@xinet.com as of 1996-01-16.]
1231 ** It does a binary search of the time_t space. Since time_t's are
1232 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
1233 ** would still be very reasonable).
1236 #ifndef WRONG
1237 #define WRONG (-1)
1238 #endif /* !defined WRONG */
1241 ** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
1244 static int
1245 increment_overflow(number, delta)
1246 int * number;
1247 int delta;
1249 int number0;
1251 number0 = *number;
1252 *number += delta;
1253 return (*number < number0) != (delta < 0);
1256 static int
1257 normalize_overflow(tensptr, unitsptr, base)
1258 int * const tensptr;
1259 int * const unitsptr;
1260 const int base;
1262 register int tensdelta;
1264 tensdelta = (*unitsptr >= 0) ?
1265 (*unitsptr / base) :
1266 (-1 - (-1 - *unitsptr) / base);
1267 *unitsptr -= tensdelta * base;
1268 return increment_overflow(tensptr, tensdelta);
1271 static int
1272 tmcomp(atmp, btmp)
1273 register const struct tm * const atmp;
1274 register const struct tm * const btmp;
1276 register int result;
1278 if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
1279 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1280 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1281 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1282 (result = (atmp->tm_min - btmp->tm_min)) == 0)
1283 result = atmp->tm_sec - btmp->tm_sec;
1284 return result;
1287 static time_t
1288 time2(tmp, funcp, offset, okayp, zone)
1289 struct tm * const tmp;
1290 void (* const funcp) P((const time_t*, long, struct tm*, const char*));
1291 const long offset;
1292 int * const okayp;
1293 const char * const zone;
1295 register const struct state * sp;
1296 register int dir;
1297 register int bits;
1298 register int i, j ;
1299 register int saved_seconds;
1300 time_t newt;
1301 time_t t;
1302 struct tm yourtm, mytm;
1304 *okayp = FALSE;
1305 yourtm = *tmp;
1306 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
1307 return WRONG;
1308 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
1309 return WRONG;
1310 if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))
1311 return WRONG;
1313 ** Turn yourtm.tm_year into an actual year number for now.
1314 ** It is converted back to an offset from TM_YEAR_BASE later.
1316 if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
1317 return WRONG;
1318 while (yourtm.tm_mday <= 0) {
1319 if (increment_overflow(&yourtm.tm_year, -1))
1320 return WRONG;
1321 i = yourtm.tm_year + (1 < yourtm.tm_mon);
1322 yourtm.tm_mday += year_lengths[isleap(i)];
1324 while (yourtm.tm_mday > DAYSPERLYEAR) {
1325 i = yourtm.tm_year + (1 < yourtm.tm_mon);
1326 yourtm.tm_mday -= year_lengths[isleap(i)];
1327 if (increment_overflow(&yourtm.tm_year, 1))
1328 return WRONG;
1330 for ( ; ; ) {
1331 i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
1332 if (yourtm.tm_mday <= i)
1333 break;
1334 yourtm.tm_mday -= i;
1335 if (++yourtm.tm_mon >= MONSPERYEAR) {
1336 yourtm.tm_mon = 0;
1337 if (increment_overflow(&yourtm.tm_year, 1))
1338 return WRONG;
1341 if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
1342 return WRONG;
1343 if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {
1345 ** We can't set tm_sec to 0, because that might push the
1346 ** time below the minimum representable time.
1347 ** Set tm_sec to 59 instead.
1348 ** This assumes that the minimum representable time is
1349 ** not in the same minute that a leap second was deleted from,
1350 ** which is a safer assumption than using 58 would be.
1352 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
1353 return WRONG;
1354 saved_seconds = yourtm.tm_sec;
1355 yourtm.tm_sec = SECSPERMIN - 1;
1356 } else {
1357 saved_seconds = yourtm.tm_sec;
1358 yourtm.tm_sec = 0;
1361 ** Divide the search space in half
1362 ** (this works whether time_t is signed or unsigned).
1364 bits = TYPE_BIT(time_t) - 1;
1366 ** If time_t is signed, then 0 is just above the median,
1367 ** assuming two's complement arithmetic.
1368 ** If time_t is unsigned, then (1 << bits) is just above the median.
1370 t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits);
1371 for ( ; ; ) {
1372 (*funcp)(&t, offset, &mytm, zone);
1373 dir = tmcomp(&mytm, &yourtm);
1374 if (dir != 0) {
1375 if (bits-- < 0)
1376 return WRONG;
1377 if (bits < 0)
1378 --t; /* may be needed if new t is minimal */
1379 else if (dir > 0)
1380 t -= ((time_t) 1) << bits;
1381 else t += ((time_t) 1) << bits;
1382 continue;
1384 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
1385 break;
1387 ** Right time, wrong type.
1388 ** Hunt for right time, right type.
1389 ** It's okay to guess wrong since the guess
1390 ** gets checked.
1393 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
1395 sp = (const struct state *)
1396 (((void *) funcp == (void *) localsub) ?
1397 lclptr : gmtptr);
1398 if (sp == NULL)
1399 return WRONG;
1400 for (i = sp->typecnt - 1; i >= 0; --i) {
1401 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
1402 continue;
1403 for (j = sp->typecnt - 1; j >= 0; --j) {
1404 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
1405 continue;
1406 newt = t + sp->ttis[j].tt_gmtoff -
1407 sp->ttis[i].tt_gmtoff;
1408 (*funcp)(&newt, offset, &mytm, zone);
1409 if (tmcomp(&mytm, &yourtm) != 0)
1410 continue;
1411 if (mytm.tm_isdst != yourtm.tm_isdst)
1412 continue;
1414 ** We have a match.
1416 t = newt;
1417 goto label;
1420 return WRONG;
1422 label:
1423 newt = t + saved_seconds;
1424 if ((newt < t) != (saved_seconds < 0))
1425 return WRONG;
1426 t = newt;
1427 (*funcp)(&t, offset, tmp, zone);
1428 *okayp = TRUE;
1429 return t;
1432 static time_t
1433 time1(tmp, funcp, offset, zone)
1434 struct tm * const tmp;
1435 void (* const funcp) P((const time_t *, long, struct tm *, const char*));
1436 const long offset;
1437 const char * const zone;
1439 register time_t t;
1440 register const struct state * sp;
1441 register int samei, otheri;
1442 int okay;
1444 if (tmp->tm_isdst > 1)
1445 tmp->tm_isdst = 1;
1446 t = time2(tmp, funcp, offset, &okay, zone);
1447 #ifdef PCTS
1449 ** PCTS code courtesy Grant Sullivan (grant@osf.org).
1451 if (okay)
1452 return t;
1453 if (tmp->tm_isdst < 0)
1454 tmp->tm_isdst = 0; /* reset to std and try again */
1455 #endif /* defined PCTS */
1456 #ifndef PCTS
1457 if (okay || tmp->tm_isdst < 0)
1458 return t;
1459 #endif /* !defined PCTS */
1461 ** We're supposed to assume that somebody took a time of one type
1462 ** and did some math on it that yielded a "struct tm" that's bad.
1463 ** We try to divine the type they started from and adjust to the
1464 ** type they need.
1467 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
1469 sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
1470 lclptr : gmtptr);
1471 if (sp == NULL)
1472 return WRONG;
1473 for (samei = sp->typecnt - 1; samei >= 0; --samei) {
1474 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
1475 continue;
1476 for (otheri = sp->typecnt - 1; otheri >= 0; --otheri) {
1477 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
1478 continue;
1479 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
1480 sp->ttis[samei].tt_gmtoff;
1481 tmp->tm_isdst = !tmp->tm_isdst;
1482 t = time2(tmp, funcp, offset, &okay, zone);
1483 if (okay)
1484 return t;
1485 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
1486 sp->ttis[samei].tt_gmtoff;
1487 tmp->tm_isdst = !tmp->tm_isdst;
1490 return WRONG;
1493 time_t
1494 ast_mktime(tmp,zone)
1495 struct tm * const tmp;
1496 const char * const zone;
1498 time_t mktime_return_value;
1499 #ifdef _THREAD_SAFE
1500 ast_mutex_lock(&lcl_mutex);
1501 #endif
1502 ast_tzset(zone);
1503 mktime_return_value = time1(tmp, localsub, 0L, zone);
1504 #ifdef _THREAD_SAFE
1505 ast_mutex_unlock(&lcl_mutex);
1506 #endif
1507 return(mktime_return_value);