4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 1995-2002 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
28 /* from Arthur Olson's 6.1 */
36 #include <stdio.h> /* for NULL */
39 #include <sys/param.h> /* for MAXPATHLEN */
42 #define FILENAME_MAX MAXPATHLEN
48 #else /* !defined __STDC__ */
51 ** Memory management functions
54 extern char * calloc();
55 extern char * malloc();
58 ** Communication with the environment
61 extern char * getenv();
64 #define P(s) (/ASTERISK s ASTERISK/)
68 #endif /* !defined __STDC__ */
73 #endif /* !defined TRUE */
75 #define ACCESS_MODE O_RDONLY
77 #define OPEN_MODE O_RDONLY
80 ** Someone might make incorrect use of a time zone abbreviation:
81 ** 1. They might reference tzname[0] before calling tzset (explicitly
83 ** 2. They might reference tzname[1] before calling tzset (explicitly
85 ** 3. They might reference tzname[1] after setting to a time zone
86 ** in which Daylight Saving Time is never observed.
87 ** 4. They might reference tzname[0] after setting to a time zone
88 ** in which Standard Time is never observed.
89 ** 5. They might reference tm.TM_ZONE after calling offtime.
90 ** What's best to do in the above cases is open to debate;
91 ** for now, we just set things up so that in any of the five cases
92 ** WILDABBR is used. Another possibility: initialize tzname[0] to the
93 ** string "tzname[0] used before set", and similarly for the other cases.
94 ** And another: initialize tzname[0] to "ERA", with an explanation in the
95 ** manual page of what this "time zone abbreviation" means (doing this so
96 ** that tzname[0] has the "normal" length of three characters).
98 static const char *WILDABBR
= " ";
100 static const char *GMT
= "GMT";
102 struct ttinfo
{ /* time type information */
103 long tt_gmtoff
; /* GMT offset in seconds */
104 int tt_isdst
; /* used to set tm_isdst */
105 int tt_abbrind
; /* abbreviation list index */
106 int tt_ttisstd
; /* TRUE if transition is std time */
114 unsigned char *types
;
117 char *last_tzload
; /* name of file tzload() last opened */
121 int r_type
; /* type of rule--see below */
122 int r_day
; /* day number of rule */
123 int r_week
; /* week number of rule */
124 int r_mon
; /* month number of rule */
125 long r_time
; /* transition time of rule */
128 #define JULIAN_DAY 0 /* Jn - Julian day */
129 #define DAY_OF_YEAR 1 /* n - day of year */
130 #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
133 ** Prototypes for static functions.
136 static int allocall
P((register struct state
* sp
));
137 static long detzcode
P((const char * codep
));
138 static void freeall
P((register struct state
* sp
));
139 static const char * getzname
P((const char * strp
, const int i
));
140 static const char * getnum
P((const char * strp
, int * nump
, int min
,
142 static const char * getsecs
P((const char * strp
, long * secsp
));
143 static const char * getoffset
P((const char * strp
, long * offsetp
));
144 static const char * getrule
P((const char * strp
, struct rule
* rulep
));
145 static void gmtload
P((struct state
* sp
));
146 static void gmtsub
P((const time_t * timep
, long offset
,
148 static void localsub
P((const time_t * timep
, long offset
,
150 static void normalize
P((int * tensptr
, int * unitsptr
, int base
));
151 static void settzname
P((void));
152 static time_t time1
P((struct tm
* tmp
, void (* funcp
)(),
154 static time_t time2
P((struct tm
*tmp
, void (* funcp
)(),
155 long offset
, int * okayp
));
156 static void timesub
P((const time_t * timep
, long offset
,
158 static int tmcomp
P((const struct tm
* atmp
,
159 const struct tm
* btmp
));
160 static time_t transtime
P((time_t janfirst
, int year
,
161 const struct rule
* rulep
, long offset
));
162 static int tzload
P((const char * name
, struct state
* sp
));
163 static int tzparse
P((const char * name
, struct state
* sp
,
166 static struct state
* lclptr
;
167 static struct state
* gmtptr
;
169 static int lcl_is_set
;
170 static int gmt_is_set
;
181 #endif /* defined S5EMUL */
185 const char * const codep
;
187 register long result
;
191 for (i
= 0; i
< 4; ++i
)
192 result
= (result
<< 8) | (codep
[i
] & 0xff);
197 ** Free up existing items pointed to by the specified "state" structure,
198 ** and allocate new ones of sizes specified by that "state" structure.
199 ** Return 0 on success; return -1 and free all previously-allocated items
204 register struct state
* const sp
;
208 if (sp
->timecnt
!= 0) {
209 sp
->ats
= (time_t *)calloc((unsigned)sp
->timecnt
,
210 (unsigned)sizeof (time_t));
214 (unsigned char *)calloc((unsigned)sp
->timecnt
,
215 (unsigned)sizeof (unsigned char));
216 if (sp
->types
== NULL
) {
222 (struct ttinfo
*)calloc((unsigned)sp
->typecnt
,
223 (unsigned)sizeof (struct ttinfo
));
224 if (sp
->ttis
== NULL
) {
228 sp
->chars
= (char *)calloc((unsigned)sp
->charcnt
+ 1,
229 (unsigned)sizeof (char));
230 if (sp
->chars
== NULL
) {
238 ** Free all the items pointed to by the specified "state" structure (except for
239 ** "chars", which might have other references to it), and zero out all the
240 ** pointers to those items.
244 register struct state
* const sp
;
247 free((char *)sp
->ttis
);
251 free((char *)sp
->types
);
255 free((char *)sp
->ats
);
264 register const struct state
* const sp
= lclptr
;
267 tzname
[0] = (char *)GMT
;
268 tzname
[1] = (char *)WILDABBR
;
274 for (i
= 0; i
< sp
->typecnt
; ++i
) {
275 register const struct ttinfo
* const ttisp
= &sp
->ttis
[i
];
277 tzname
[ttisp
->tt_isdst
] =
278 (char *) &sp
->chars
[ttisp
->tt_abbrind
];
281 if (i
== 0 || !ttisp
->tt_isdst
)
282 timezone
= -(ttisp
->tt_gmtoff
);
283 if (i
== 0 || ttisp
->tt_isdst
)
284 altzone
= -(ttisp
->tt_gmtoff
);
287 ** And to get the latest zone names into tzname. . .
289 for (i
= 0; i
< sp
->timecnt
; ++i
) {
290 register const struct ttinfo
* const ttisp
=
291 &sp
->ttis
[sp
->types
[i
]];
293 tzname
[ttisp
->tt_isdst
] =
294 (char *) &sp
->chars
[ttisp
->tt_abbrind
];
300 ** Maximum size of a time zone file.
302 #define MAX_TZFILESZ (sizeof (struct tzhead) + \
303 TZ_MAX_TIMES * (4 + sizeof (char)) + \
304 TZ_MAX_TYPES * (4 + 2 * sizeof (char)) + \
305 TZ_MAX_CHARS * sizeof (char) + \
306 TZ_MAX_LEAPS * 2 * 4 + \
307 TZ_MAX_TYPES * sizeof (char))
311 register const char * name
;
312 register struct state
* const sp
;
314 register const char * p
;
318 if (name
== NULL
&& (name
= (const char *)TZDEFAULT
) == NULL
)
321 register int doaccess
;
322 char fullname
[FILENAME_MAX
+ 1];
326 doaccess
= name
[0] == '/';
328 if ((p
= TZDIR
) == NULL
)
330 if ((strlen(p
) + strlen(name
) + 1) >= sizeof fullname
)
332 (void) strcpy(fullname
, p
);
333 (void) strcat(fullname
, "/");
334 (void) strcat(fullname
, name
);
336 ** Set doaccess if '.' (as in "../") shows up in name.
338 if (strchr(name
, '.') != NULL
)
342 if (sp
->last_tzload
&& strcmp(sp
->last_tzload
, name
) == 0)
344 if (doaccess
&& access(name
, ACCESS_MODE
) != 0)
346 if ((fid
= open(name
, OPEN_MODE
)) == -1)
350 register const struct tzhead
* tzhp
;
351 char buf
[MAX_TZFILESZ
];
355 i
= read(fid
, buf
, sizeof buf
);
356 if (close(fid
) != 0 || i
< sizeof *tzhp
)
358 tzhp
= (struct tzhead
*) buf
;
359 ttisstdcnt
= (int) detzcode(tzhp
->tzh_ttisstdcnt
);
360 leapcnt
= (int) detzcode(tzhp
->tzh_leapcnt
);
361 sp
->timecnt
= (int) detzcode(tzhp
->tzh_timecnt
);
362 sp
->typecnt
= (int) detzcode(tzhp
->tzh_typecnt
);
363 sp
->charcnt
= (int) detzcode(tzhp
->tzh_charcnt
);
364 if (leapcnt
< 0 || leapcnt
> TZ_MAX_LEAPS
||
365 sp
->typecnt
<= 0 || sp
->typecnt
> TZ_MAX_TYPES
||
366 sp
->timecnt
< 0 || sp
->timecnt
> TZ_MAX_TIMES
||
367 sp
->charcnt
< 0 || sp
->charcnt
> TZ_MAX_CHARS
||
368 (ttisstdcnt
!= sp
->typecnt
&& ttisstdcnt
!= 0))
370 if (i
< sizeof *tzhp
+
371 sp
->timecnt
* (4 + sizeof (char)) +
372 sp
->typecnt
* (4 + 2 * sizeof (char)) +
373 sp
->charcnt
* sizeof (char) +
375 ttisstdcnt
* sizeof (char))
377 if (allocall(sp
) < 0)
379 p
= buf
+ sizeof *tzhp
;
380 for (i
= 0; i
< sp
->timecnt
; ++i
) {
381 sp
->ats
[i
] = detzcode(p
);
384 for (i
= 0; i
< sp
->timecnt
; ++i
) {
385 sp
->types
[i
] = (unsigned char) *p
++;
386 if (sp
->types
[i
] >= sp
->typecnt
)
389 for (i
= 0; i
< sp
->typecnt
; ++i
) {
390 register struct ttinfo
* ttisp
;
392 ttisp
= &sp
->ttis
[i
];
393 ttisp
->tt_gmtoff
= detzcode(p
);
395 ttisp
->tt_isdst
= (unsigned char) *p
++;
396 if (ttisp
->tt_isdst
!= 0 && ttisp
->tt_isdst
!= 1)
398 ttisp
->tt_abbrind
= (unsigned char) *p
++;
399 if (ttisp
->tt_abbrind
< 0 ||
400 ttisp
->tt_abbrind
> sp
->charcnt
)
403 for (i
= 0; i
< sp
->charcnt
-1; ++i
)
405 sp
->chars
[i
] = '\0'; /* ensure '\0' at end */
406 p
+= (4 + 4) * leapcnt
; /* skip leap seconds list */
407 for (i
= 0; i
< sp
->typecnt
; ++i
) {
408 register struct ttinfo
* ttisp
;
410 ttisp
= &sp
->ttis
[i
];
412 ttisp
->tt_ttisstd
= FALSE
;
414 ttisp
->tt_ttisstd
= *p
++;
415 if (ttisp
->tt_ttisstd
!= TRUE
&&
416 ttisp
->tt_ttisstd
!= FALSE
)
422 free(sp
->last_tzload
);
423 sp
->last_tzload
= strdup(name
);
427 static const int mon_lengths
[2][MONSPERYEAR
] = {
428 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
429 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
432 static const int year_lengths
[2] = {
433 DAYSPERNYEAR
, DAYSPERLYEAR
437 ** Given a pointer into a time zone string, scan until a character that is not
438 ** a valid character in a zone name is found. Return a pointer to that
440 ** Support both quoted and unquoted timezones.
444 getzname(strp
, quoted
)
451 while ((c
= (unsigned char)*strp
) != '\0' &&
452 (isalnum(c
) || (c
== '+') || (c
== '-')))
455 while ((c
= (unsigned char)*strp
) != '\0' && !isdigit(c
)
456 && (c
!= ',') && (c
!= '-') && (c
!= '+'))
463 ** Given a pointer into a time zone string, extract a number from that string.
464 ** Check that the number is within a specified range; if it is not, return
466 ** Otherwise, return a pointer to the first character not part of the number.
470 getnum(strp
, nump
, min
, max
)
471 register const char * strp
;
479 if (strp
== NULL
|| !isdigit(*strp
))
482 while ((c
= *strp
) != '\0' && isdigit(c
)) {
483 num
= num
* 10 + (c
- '0');
485 return NULL
; /* illegal value */
489 return NULL
; /* illegal value */
495 ** Given a pointer into a time zone string, extract a number of seconds,
496 ** in hh[:mm[:ss]] form, from the string.
497 ** If any error occurs, return NULL.
498 ** Otherwise, return a pointer to the first character not part of the number
504 register const char * strp
;
509 strp
= getnum(strp
, &num
, 0, HOURSPERDAY
);
512 *secsp
= num
* SECSPERHOUR
;
515 strp
= getnum(strp
, &num
, 0, MINSPERHOUR
- 1);
518 *secsp
+= num
* SECSPERMIN
;
521 strp
= getnum(strp
, &num
, 0, SECSPERMIN
- 1);
531 ** Given a pointer into a time zone string, extract an offset, in
532 ** [+-]hh[:mm[:ss]] form, from the string.
533 ** If any error occurs, return NULL.
534 ** Otherwise, return a pointer to the first character not part of the time.
538 getoffset(strp
, offsetp
)
539 register const char * strp
;
540 long * const offsetp
;
547 } else if (isdigit(*strp
) || *strp
++ == '+')
549 else return NULL
; /* illegal offset */
550 strp
= getsecs(strp
, offsetp
);
552 return NULL
; /* illegal time */
554 *offsetp
= -*offsetp
;
559 ** Given a pointer into a time zone string, extract a rule in the form
560 ** date[/time]. See POSIX section 8 for the format of "date" and "time".
561 ** If a valid rule is not found, return NULL.
562 ** Otherwise, return a pointer to the first character not part of the rule.
568 register struct rule
* const rulep
;
574 rulep
->r_type
= JULIAN_DAY
;
576 strp
= getnum(strp
, &rulep
->r_day
, 1, DAYSPERNYEAR
);
577 } else if (*strp
== 'M') {
581 rulep
->r_type
= MONTH_NTH_DAY_OF_WEEK
;
583 strp
= getnum(strp
, &rulep
->r_mon
, 1, MONSPERYEAR
);
588 strp
= getnum(strp
, &rulep
->r_week
, 1, 5);
593 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERWEEK
- 1);
594 } else if (isdigit(*strp
)) {
598 rulep
->r_type
= DAY_OF_YEAR
;
599 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERLYEAR
- 1);
600 } else return NULL
; /* invalid format */
608 strp
= getsecs(strp
, &rulep
->r_time
);
609 } else rulep
->r_time
= 2 * SECSPERHOUR
; /* default = 2:00:00 */
614 ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
615 ** year, a rule, and the offset from GMT at the time that rule takes effect,
616 ** calculate the Epoch-relative time that rule takes effect.
620 transtime(janfirst
, year
, rulep
, offset
)
621 const time_t janfirst
;
623 register const struct rule
* const rulep
;
626 register int leapyear
;
627 register time_t value
;
629 int d
, m1
, yy0
, yy1
, yy2
, dow
;
631 leapyear
= isleap(year
);
632 switch (rulep
->r_type
) {
636 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
638 ** In non-leap years, or if the day number is 59 or less, just
639 ** add SECSPERDAY times the day number-1 to the time of
640 ** January 1, midnight, to get the day.
642 value
= janfirst
+ (rulep
->r_day
- 1) * SECSPERDAY
;
643 if (leapyear
&& rulep
->r_day
>= 60)
650 ** Just add SECSPERDAY times the day number to the time of
651 ** January 1, midnight, to get the day.
653 value
= janfirst
+ rulep
->r_day
* SECSPERDAY
;
656 case MONTH_NTH_DAY_OF_WEEK
:
658 ** Mm.n.d - nth "dth day" of month m.
661 for (i
= 0; i
< rulep
->r_mon
- 1; ++i
)
662 value
+= mon_lengths
[leapyear
][i
] * SECSPERDAY
;
665 ** Use Zeller's Congruence to get day-of-week of first day of
668 m1
= (rulep
->r_mon
+ 9) % 12 + 1;
669 yy0
= (rulep
->r_mon
<= 2) ? (year
- 1) : year
;
672 dow
= ((26 * m1
- 2) / 10 +
673 1 + yy2
+ yy2
/ 4 + yy1
/ 4 - 2 * yy1
) % 7;
678 ** "dow" is the day-of-week of the first day of the month. Get
679 ** the day-of-month (zero-origin) of the first "dow" day of the
682 d
= rulep
->r_day
- dow
;
685 for (i
= 1; i
< rulep
->r_week
; ++i
) {
686 if (d
+ DAYSPERWEEK
>=
687 mon_lengths
[leapyear
][rulep
->r_mon
- 1])
693 ** "d" is the day-of-month (zero-origin) of the day we want.
695 value
+= d
* SECSPERDAY
;
700 ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
701 ** question. To get the Epoch-relative time of the specified local
702 ** time on that day, add the transition time and the current offset
705 return value
+ rulep
->r_time
+ offset
;
709 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
714 tzparse(name
, sp
, lastditch
)
716 struct state
* const sp
;
719 const char * stdname
;
720 const char * dstname
;
726 unsigned char * typep
;
732 stdlen
= strlen(name
); /* length of standard zone name */
734 if (stdlen
>= sizeof sp
->chars
)
735 stdlen
= (sizeof sp
->chars
) - 1;
740 name
= getzname(name
, 1);
744 stdlen
= name
- stdname
;
747 name
= getzname(name
, 0);
748 stdlen
= name
- stdname
;
756 name
= getoffset(name
, &stdoffset
);
765 name
= getzname(name
, 1);
769 dstlen
= name
- dstname
;
772 name
= getzname(name
, 0);
773 dstlen
= name
- dstname
;
777 if (*name
!= '\0' && *name
!= ',' && *name
!= ';') {
778 name
= getoffset(name
, &dstoffset
);
781 } else dstoffset
= stdoffset
- SECSPERHOUR
;
782 if (*name
== ',' || *name
== ';') {
786 register time_t janfirst
;
791 if ((name
= getrule(name
, &start
)) == NULL
)
795 if ((name
= getrule(name
, &end
)) == NULL
)
799 sp
->typecnt
= 2; /* standard time and DST */
801 ** Two transitions per year, from EPOCH_YEAR to 2037.
803 sp
->timecnt
= 2 * (2037 - EPOCH_YEAR
+ 1);
804 if (sp
->timecnt
> TZ_MAX_TIMES
)
806 sp
->charcnt
= stdlen
+ 1 + dstlen
+ 1;
807 if (allocall(sp
) < 0)
809 sp
->ttis
[0].tt_gmtoff
= -dstoffset
;
810 sp
->ttis
[0].tt_isdst
= 1;
811 sp
->ttis
[0].tt_abbrind
= stdlen
+ 1;
812 sp
->ttis
[1].tt_gmtoff
= -stdoffset
;
813 sp
->ttis
[1].tt_isdst
= 0;
814 sp
->ttis
[1].tt_abbrind
= 0;
818 for (year
= EPOCH_YEAR
; year
<= 2037; ++year
) {
819 starttime
= transtime(janfirst
, year
, &start
,
821 endtime
= transtime(janfirst
, year
, &end
,
823 if (starttime
> endtime
) {
825 *typep
++ = 1; /* DST ends */
827 *typep
++ = 0; /* DST begins */
830 *typep
++ = 0; /* DST begins */
832 *typep
++ = 1; /* DST ends */
835 year_lengths
[isleap(year
)] * SECSPERDAY
;
848 if (tzload(TZDEFRULES
, sp
) != 0) {
853 ** Discard zone abbreviations from file, and allocate
854 ** space for the ones from TZ.
857 sp
->charcnt
= stdlen
+ 1 + dstlen
+ 1;
858 sp
->chars
= (char *)calloc((unsigned)sp
->charcnt
,
859 (unsigned)sizeof (char));
861 ** Compute the difference between the real and
862 ** prototype standard and summer time offsets
863 ** from GMT, and put the real standard and summer
864 ** time offsets into the rules in place of the
865 ** prototype offsets.
871 for (i
= 0; i
< sp
->typecnt
; ++i
) {
872 if (sp
->ttis
[i
].tt_isdst
) {
875 sp
->ttis
[i
].tt_gmtoff
+ dstoffset
;
876 if (sawdst
&& (oldfix
!= dstfix
))
878 sp
->ttis
[i
].tt_gmtoff
= -dstoffset
;
879 sp
->ttis
[i
].tt_abbrind
= stdlen
+ 1;
884 sp
->ttis
[i
].tt_gmtoff
+ stdoffset
;
885 if (sawstd
&& (oldfix
!= stdfix
))
887 sp
->ttis
[i
].tt_gmtoff
= -stdoffset
;
888 sp
->ttis
[i
].tt_abbrind
= 0;
893 ** Make sure we have both standard and summer time.
895 if (!sawdst
|| !sawstd
)
898 ** Now correct the transition times by shifting
899 ** them by the difference between the real and
900 ** prototype offsets. Note that this difference
901 ** can be different in standard and summer time;
902 ** the prototype probably has a 1-hour difference
903 ** between standard and summer time, but a different
904 ** difference can be specified in TZ.
906 isdst
= FALSE
; /* we start in standard time */
907 for (i
= 0; i
< sp
->timecnt
; ++i
) {
908 register const struct ttinfo
* ttisp
;
911 ** If summer time is in effect, and the
912 ** transition time was not specified as
913 ** standard time, add the summer time
914 ** offset to the transition time;
915 ** otherwise, add the standard time offset
916 ** to the transition time.
918 ttisp
= &sp
->ttis
[sp
->types
[i
]];
920 (isdst
&& !ttisp
->tt_ttisstd
) ?
922 isdst
= ttisp
->tt_isdst
;
927 sp
->typecnt
= 1; /* only standard time */
929 sp
->charcnt
= stdlen
+ 1;
930 if (allocall(sp
) < 0)
932 sp
->ttis
[0].tt_gmtoff
= -stdoffset
;
933 sp
->ttis
[0].tt_isdst
= 0;
934 sp
->ttis
[0].tt_abbrind
= 0;
937 (void) strncpy(cp
, stdname
, stdlen
);
941 (void) strncpy(cp
, dstname
, dstlen
);
942 *(cp
+ dstlen
) = '\0';
949 struct state
* const sp
;
951 if (tzload(GMT
, sp
) != 0)
952 (void) tzparse(GMT
, sp
, TRUE
);
959 if (lclptr
== NULL
) {
960 lclptr
= (struct state
*) calloc(1, (unsigned)sizeof *lclptr
);
961 if (lclptr
== NULL
) {
963 settzname(); /* all we can do */
968 if (tzload((char *) NULL
, lclptr
) != 0)
978 register const char * name
;
980 name
= (const char *)getenv("TZ");
986 if (lclptr
== NULL
) {
987 lclptr
= (struct state
*) calloc(1, (unsigned)sizeof *lclptr
);
988 if (lclptr
== NULL
) {
990 settzname(); /* all we can do */
997 ** User wants it fast rather than right.
1000 lclptr
->typecnt
= 1;
1001 lclptr
->charcnt
= sizeof GMT
;
1002 if (allocall(lclptr
) < 0)
1004 lclptr
->ttis
[0].tt_gmtoff
= 0;
1005 lclptr
->ttis
[0].tt_abbrind
= 0;
1006 (void) strcpy(lclptr
->chars
, GMT
);
1007 } else if (tzload(name
, lclptr
) != 0)
1008 if (name
[0] == ':' || tzparse(name
, lclptr
, FALSE
) != 0)
1009 (void) tzparse(name
, lclptr
, TRUE
);
1016 ** The easy way to behave "as if no library function calls" localtime
1017 ** is to not call it--so we drop its guts into "localsub", which can be
1018 ** freely called. (And no, the PANS doesn't require the above behavior--
1019 ** but it *is* desirable.)
1021 ** The unused offset argument is for the benefit of mktime variants.
1024 static struct tm tm
;
1028 localsub(timep
, offset
, tmp
)
1029 const time_t * const timep
;
1031 struct tm
* const tmp
;
1033 register const struct state
* sp
;
1034 register const struct ttinfo
* ttisp
;
1036 const time_t t
= *timep
;
1042 gmtsub(timep
, offset
, tmp
);
1045 if (sp
->timecnt
== 0 || t
< sp
->ats
[0]) {
1047 while (sp
->ttis
[i
].tt_isdst
)
1048 if (++i
>= sp
->typecnt
) {
1053 for (i
= 1; i
< sp
->timecnt
; ++i
)
1056 i
= sp
->types
[i
- 1];
1058 ttisp
= &sp
->ttis
[i
];
1059 timesub(&t
, ttisp
->tt_gmtoff
, tmp
);
1060 tmp
->tm_isdst
= ttisp
->tt_isdst
;
1062 tzname
[tmp
->tm_isdst
] = (char *) &sp
->chars
[ttisp
->tt_abbrind
];
1064 tmp
->tm_zone
= &sp
->chars
[ttisp
->tt_abbrind
];
1069 const time_t * const timep
;
1071 time_t temp_time
= *(const time_t*)timep
;
1073 _ltzset(&temp_time
); /*
1074 * base localtime calls this to initialize
1075 * some things, so we'll do it here, too.
1077 localsub(timep
, 0L, &tm
);
1082 ** gmtsub is to gmtime as localsub is to localtime.
1086 gmtsub(timep
, offset
, tmp
)
1087 const time_t * const timep
;
1089 struct tm
* const tmp
;
1093 gmtptr
= (struct state
*) calloc(1, (unsigned)sizeof *gmtptr
);
1097 timesub(timep
, offset
, tmp
);
1099 ** Could get fancy here and deliver something such as
1100 ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
1101 ** but this is no time for a treasure hunt.
1104 tmp
->tm_zone
= (char *)WILDABBR
;
1107 tmp
->tm_zone
= (char *)GMT
;
1108 else tmp
->tm_zone
= gmtptr
->chars
;
1114 const time_t * const timep
;
1116 gmtsub(timep
, 0L, &tm
);
1121 offtime(timep
, offset
)
1122 const time_t * const timep
;
1125 gmtsub(timep
, offset
, &tm
);
1130 timesub(timep
, offset
, tmp
)
1131 const time_t * const timep
;
1133 register struct tm
* const tmp
;
1139 register const int * ip
;
1141 days
= *timep
/ SECSPERDAY
;
1142 rem
= *timep
% SECSPERDAY
;
1148 while (rem
>= SECSPERDAY
) {
1152 tmp
->tm_hour
= (int) (rem
/ SECSPERHOUR
);
1153 rem
= rem
% SECSPERHOUR
;
1154 tmp
->tm_min
= (int) (rem
/ SECSPERMIN
);
1155 tmp
->tm_sec
= (int) (rem
% SECSPERMIN
);
1156 tmp
->tm_wday
= (int) ((EPOCH_WDAY
+ days
) % DAYSPERWEEK
);
1157 if (tmp
->tm_wday
< 0)
1158 tmp
->tm_wday
+= DAYSPERWEEK
;
1163 if (days
< (long) year_lengths
[yleap
])
1166 days
= days
- (long) year_lengths
[yleap
];
1171 days
= days
+ (long) year_lengths
[yleap
];
1173 tmp
->tm_year
= y
- TM_YEAR_BASE
;
1174 tmp
->tm_yday
= (int) days
;
1175 ip
= mon_lengths
[yleap
];
1176 for (tmp
->tm_mon
= 0; days
>= (long) ip
[tmp
->tm_mon
]; ++(tmp
->tm_mon
))
1177 days
= days
- (long) ip
[tmp
->tm_mon
];
1178 tmp
->tm_mday
= (int) (days
+ 1);
1180 tmp
->tm_gmtoff
= offset
;
1184 ** Adapted from code provided by Robert Elz, who writes:
1185 ** The "best" way to do mktime I think is based on an idea of Bob
1186 ** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
1187 ** It does a binary search of the time_t space. Since time_t's are
1188 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
1189 ** would still be very reasonable).
1194 #endif /* !defined WRONG */
1197 normalize(tensptr
, unitsptr
, base
)
1198 int * const tensptr
;
1199 int * const unitsptr
;
1204 if (*unitsptr
>= base
) {
1205 *tensptr
+= *unitsptr
/ base
;
1207 } else if (*unitsptr
< 0) {
1208 /* tmp has the range 0 to abs(*unitptr) -1 */
1209 tmp
= -1 - (*unitsptr
);
1210 *tensptr
-= (tmp
/base
+ 1);
1211 *unitsptr
= (base
- 1) - (tmp
% base
);
1217 register const struct tm
* const atmp
;
1218 register const struct tm
* const btmp
;
1220 register int result
;
1222 if ((result
= (atmp
->tm_year
- btmp
->tm_year
)) == 0 &&
1223 (result
= (atmp
->tm_mon
- btmp
->tm_mon
)) == 0 &&
1224 (result
= (atmp
->tm_mday
- btmp
->tm_mday
)) == 0 &&
1225 (result
= (atmp
->tm_hour
- btmp
->tm_hour
)) == 0 &&
1226 (result
= (atmp
->tm_min
- btmp
->tm_min
)) == 0)
1227 result
= atmp
->tm_sec
- btmp
->tm_sec
;
1232 time2(tmp
, funcp
, offset
, okayp
)
1233 struct tm
* const tmp
;
1234 void (* const funcp
)();
1238 register const struct state
* sp
;
1242 register int saved_seconds
;
1245 struct tm yourtm
, mytm
;
1249 if (yourtm
.tm_sec
>= SECSPERMIN
+ 2 || yourtm
.tm_sec
< 0)
1250 normalize(&yourtm
.tm_min
, &yourtm
.tm_sec
, SECSPERMIN
);
1251 normalize(&yourtm
.tm_hour
, &yourtm
.tm_min
, MINSPERHOUR
);
1252 normalize(&yourtm
.tm_mday
, &yourtm
.tm_hour
, HOURSPERDAY
);
1253 normalize(&yourtm
.tm_year
, &yourtm
.tm_mon
, MONSPERYEAR
);
1254 while (yourtm
.tm_mday
<= 0) {
1255 if (yourtm
.tm_mon
== 0) {
1260 mon_lengths
[isleap(yourtm
.tm_year
+
1261 TM_YEAR_BASE
)][--yourtm
.tm_mon
];
1262 if (yourtm
.tm_mon
>= MONSPERYEAR
) {
1268 i
= mon_lengths
[isleap(yourtm
.tm_year
+
1269 TM_YEAR_BASE
)][yourtm
.tm_mon
];
1270 if (yourtm
.tm_mday
<= i
)
1272 yourtm
.tm_mday
-= i
;
1273 if (++yourtm
.tm_mon
>= MONSPERYEAR
) {
1278 saved_seconds
= yourtm
.tm_sec
;
1281 ** Calculate the number of magnitude bits in a time_t
1282 ** (this works regardless of whether time_t is
1283 ** signed or unsigned, though lint complains if unsigned).
1285 for (bits
= 0, t
= 1; t
> 0; ++bits
, t
<<= 1)
1288 ** If time_t is signed, then 0 is the median value,
1289 ** if time_t is unsigned, then 1 << bits is median.
1291 t
= (t
< 0) ? 0 : ((time_t) 1 << bits
);
1293 (*funcp
)(&t
, offset
, &mytm
);
1294 dir
= tmcomp(&mytm
, &yourtm
);
1301 t
-= (time_t) 1 << bits
;
1302 else t
+= (time_t) 1 << bits
;
1305 if (yourtm
.tm_isdst
< 0 || mytm
.tm_isdst
== yourtm
.tm_isdst
)
1308 ** Right time, wrong type.
1309 ** Hunt for right time, right type.
1310 ** It's okay to guess wrong since the guess
1313 sp
= (const struct state
*)
1314 ((funcp
== localsub
) ? lclptr
: gmtptr
);
1317 for (i
= 0; i
< sp
->typecnt
; ++i
) {
1318 if (sp
->ttis
[i
].tt_isdst
!= yourtm
.tm_isdst
)
1320 for (j
= 0; j
< sp
->typecnt
; ++j
) {
1321 if (sp
->ttis
[j
].tt_isdst
== yourtm
.tm_isdst
)
1323 newt
= t
+ sp
->ttis
[j
].tt_gmtoff
-
1324 sp
->ttis
[i
].tt_gmtoff
;
1325 (*funcp
)(&newt
, offset
, &mytm
);
1326 if (tmcomp(&mytm
, &yourtm
) != 0)
1328 if (mytm
.tm_isdst
!= yourtm
.tm_isdst
)
1341 (*funcp
)(&t
, offset
, tmp
);
1347 time1(tmp
, funcp
, offset
)
1348 struct tm
* const tmp
;
1349 void (* const funcp
)();
1353 register const struct state
* sp
;
1354 register int samei
, otheri
;
1358 if (tmp
->tm_isdst
> 1)
1360 t
= time2(tmp
, funcp
, offset
, &okay
);
1361 if (okay
|| tmp
->tm_isdst
< 0)
1364 ** We're supposed to assume that somebody took a time of one type
1365 ** and did some math on it that yielded a "struct tm" that's bad.
1366 ** We try to divine the type they started from and adjust to the
1369 sp
= (const struct state
*) ((funcp
== localsub
) ? lclptr
: gmtptr
);
1372 for (samei
= 0; samei
< sp
->typecnt
; ++samei
) {
1373 if (sp
->ttis
[samei
].tt_isdst
!= tmp
->tm_isdst
)
1375 for (otheri
= 0; otheri
< sp
->typecnt
; ++otheri
) {
1376 if (sp
->ttis
[otheri
].tt_isdst
== tmp
->tm_isdst
)
1378 tmp
->tm_sec
+= sp
->ttis
[otheri
].tt_gmtoff
-
1379 sp
->ttis
[samei
].tt_gmtoff
;
1380 tmp
->tm_isdst
= !tmp
->tm_isdst
;
1381 t
= time2(tmp
, funcp
, offset
, &okay
);
1384 tmp
->tm_sec
-= sp
->ttis
[otheri
].tt_gmtoff
-
1385 sp
->ttis
[samei
].tt_gmtoff
;
1386 tmp
->tm_isdst
= !tmp
->tm_isdst
;
1394 struct tm
* const tmp
;
1396 return time1(tmp
, localsub
, 0L);
1401 struct tm
* const tmp
;
1409 struct tm
* const tmp
;
1411 return time1(tmp
, gmtsub
, 0L);
1415 timeoff(tmp
, offset
)
1416 struct tm
* const tmp
;
1420 return time1(tmp
, gmtsub
, offset
);