* Copyright (c) 1987, 1989 Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Arthur David Olson of the National Cancer Institute.
* %sccs.include.redist.c%
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid
[] = "@(#)ctime.c 5.23 (Berkeley) %G%";
#endif /* LIBC_SCCS and not lint */
** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
** POSIX-style TZ environment variable handling from Guy Harris
#define alloc_size_t size_t
#define qsort_size_t size_t
#define fread_size_t size_t
#define fwrite_size_t size_t
#else /* !defined __STDC__ */
typedef char * genericptr_t
;
typedef unsigned alloc_size_t
;
typedef int qsort_size_t
;
typedef int fread_size_t
;
typedef int fwrite_size_t
;
#endif /* !defined __STDC__ */
#define FILENAME_MAX MAXPATHLEN
#define ACCESS_MODE O_RDONLY
#define OPEN_MODE O_RDONLY
** Someone might make incorrect use of a time zone abbreviation:
** 1. They might reference tzname[0] before calling tzset (explicitly
** 2. They might reference tzname[1] before calling tzset (explicitly
** 3. They might reference tzname[1] after setting to a time zone
** in which Daylight Saving Time is never observed.
** 4. They might reference tzname[0] after setting to a time zone
** in which Standard Time is never observed.
** 5. They might reference tm.TM_ZONE after calling offtime.
** What's best to do in the above cases is open to debate;
** for now, we just set things up so that in any of the five cases
** WILDABBR is used. Another possibility: initialize tzname[0] to the
** string "tzname[0] used before set", and similarly for the other cases.
** And another: initialize tzname[0] to "ERA", with an explanation in the
** manual page of what this "time zone abbreviation" means (doing this so
** that tzname[0] has the "normal" length of three characters).
#endif /* !defined WILDABBR */
#endif /* !defined TRUE */
static const char GMT
[] = "GMT";
struct ttinfo
{ /* time type information */
long tt_gmtoff
; /* GMT offset in seconds */
int tt_isdst
; /* used to set tm_isdst */
int tt_abbrind
; /* abbreviation list index */
int tt_ttisstd
; /* TRUE if transition is std time */
struct lsinfo
{ /* leap second information */
time_t ls_trans
; /* transition time */
long ls_corr
; /* correction to apply */
time_t ats
[TZ_MAX_TIMES
];
unsigned char types
[TZ_MAX_TIMES
];
struct ttinfo ttis
[TZ_MAX_TYPES
];
char chars
[(TZ_MAX_CHARS
+ 1 > sizeof GMT
) ?
TZ_MAX_CHARS
+ 1 : sizeof GMT
];
struct lsinfo lsis
[TZ_MAX_LEAPS
];
int r_type
; /* type of rule--see below */
int r_day
; /* day number of rule */
int r_week
; /* week number of rule */
int r_mon
; /* month number of rule */
long r_time
; /* transition time of rule */
#define JULIAN_DAY 0 /* Jn - Julian day */
#define DAY_OF_YEAR 1 /* n - day of year */
#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
** Prototypes for static functions.
static long detzcode
P((const char * codep
));
static const char * getzname
P((const char * strp
));
static const char * getnum
P((const char * strp
, int * nump
, int min
,
static const char * getsecs
P((const char * strp
, long * secsp
));
static const char * getoffset
P((const char * strp
, long * offsetp
));
static const char * getrule
P((const char * strp
, struct rule
* rulep
));
static void gmtload
P((struct state
* sp
));
static void gmtsub
P((const time_t * timep
, long offset
,
static void localsub
P((const time_t * timep
, long offset
,
static void normalize
P((int * tensptr
, int * unitsptr
, int base
));
static void settzname
P((void));
static time_t time1
P((struct tm
* tmp
, void (* funcp
)(),
static time_t time2
P((struct tm
*tmp
, void (* funcp
)(),
long offset
, int * okayp
));
static void timesub
P((const time_t * timep
, long offset
,
const struct state
* sp
, struct tm
* tmp
));
static int tmcomp
P((const struct tm
* atmp
,
const struct tm
* btmp
));
static time_t transtime
P((time_t janfirst
, int year
,
const struct rule
* rulep
, long offset
));
static int tzload
P((const char * name
, struct state
* sp
));
static int tzparse
P((const char * name
, struct state
* sp
,
static struct state
* lclptr
;
static struct state
* gmtptr
;
#endif /* defined ALL_STATE */
static struct state lclmem
;
static struct state gmtmem
;
#endif /* defined USG_COMPAT */
#endif /* defined ALTZONE */
const char * const codep
;
result
= (result
<< 8) | (codep
[i
] & 0xff);
register const struct state
* const sp
= lclptr
;
#endif /* defined USG_COMPAT */
#endif /* defined ALTZONE */
tzname
[0] = tzname
[1] = GMT
;
#endif /* defined ALL_STATE */
for (i
= 0; i
< sp
->typecnt
; ++i
) {
register const struct ttinfo
* const ttisp
= &sp
->ttis
[i
];
tzname
[ttisp
->tt_isdst
] =
(char *) &sp
->chars
[ttisp
->tt_abbrind
];
if (i
== 0 || !ttisp
->tt_isdst
)
timezone
= -(ttisp
->tt_gmtoff
);
#endif /* defined USG_COMPAT */
if (i
== 0 || ttisp
->tt_isdst
)
altzone
= -(ttisp
->tt_gmtoff
);
#endif /* defined ALTZONE */
** And to get the latest zone names into tzname. . .
for (i
= 0; i
< sp
->timecnt
; ++i
) {
register const struct ttinfo
* const ttisp
=
tzname
[ttisp
->tt_isdst
] =
(char *) &sp
->chars
[ttisp
->tt_abbrind
];
register const char * name
;
register struct state
* const sp
;
if (name
== NULL
&& (name
= TZDEFAULT
) == NULL
)
char fullname
[FILENAME_MAX
+ 1];
if ((strlen(p
) + strlen(name
) + 1) >= sizeof fullname
)
(void) strcpy(fullname
, p
);
(void) strcat(fullname
, "/");
(void) strcat(fullname
, name
);
if ((fid
= open(name
, OPEN_MODE
)) == -1)
register const struct tzhead
* tzhp
;
char buf
[sizeof *sp
+ sizeof *tzhp
];
i
= read(fid
, buf
, sizeof buf
);
if (close(fid
) != 0 || i
< sizeof *tzhp
)
tzhp
= (struct tzhead
*) buf
;
ttisstdcnt
= (int) detzcode(tzhp
->tzh_ttisstdcnt
);
sp
->leapcnt
= (int) detzcode(tzhp
->tzh_leapcnt
);
sp
->timecnt
= (int) detzcode(tzhp
->tzh_timecnt
);
sp
->typecnt
= (int) detzcode(tzhp
->tzh_typecnt
);
sp
->charcnt
= (int) detzcode(tzhp
->tzh_charcnt
);
if (sp
->leapcnt
< 0 || sp
->leapcnt
> TZ_MAX_LEAPS
||
sp
->typecnt
<= 0 || sp
->typecnt
> TZ_MAX_TYPES
||
sp
->timecnt
< 0 || sp
->timecnt
> TZ_MAX_TIMES
||
sp
->charcnt
< 0 || sp
->charcnt
> TZ_MAX_CHARS
||
(ttisstdcnt
!= sp
->typecnt
&& ttisstdcnt
!= 0))
sp
->timecnt
* (4 + sizeof (char)) +
sp
->typecnt
* (4 + 2 * sizeof (char)) +
sp
->charcnt
* sizeof (char) +
ttisstdcnt
* sizeof (char))
for (i
= 0; i
< sp
->timecnt
; ++i
) {
sp
->ats
[i
] = detzcode(p
);
for (i
= 0; i
< sp
->timecnt
; ++i
) {
sp
->types
[i
] = (unsigned char) *p
++;
if (sp
->types
[i
] >= sp
->typecnt
)
for (i
= 0; i
< sp
->typecnt
; ++i
) {
register struct ttinfo
* ttisp
;
ttisp
->tt_gmtoff
= detzcode(p
);
ttisp
->tt_isdst
= (unsigned char) *p
++;
if (ttisp
->tt_isdst
!= 0 && ttisp
->tt_isdst
!= 1)
ttisp
->tt_abbrind
= (unsigned char) *p
++;
if (ttisp
->tt_abbrind
< 0 ||
ttisp
->tt_abbrind
> sp
->charcnt
)
for (i
= 0; i
< sp
->charcnt
; ++i
)
sp
->chars
[i
] = '\0'; /* ensure '\0' at end */
for (i
= 0; i
< sp
->leapcnt
; ++i
) {
register struct lsinfo
* lsisp
;
lsisp
->ls_trans
= detzcode(p
);
lsisp
->ls_corr
= detzcode(p
);
for (i
= 0; i
< sp
->typecnt
; ++i
) {
register struct ttinfo
* ttisp
;
ttisp
->tt_ttisstd
= FALSE
;
ttisp
->tt_ttisstd
= *p
++;
if (ttisp
->tt_ttisstd
!= TRUE
&&
ttisp
->tt_ttisstd
!= FALSE
)
static const int mon_lengths
[2][MONSPERYEAR
] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
static const int year_lengths
[2] = {
DAYSPERNYEAR
, DAYSPERLYEAR
** Given a pointer into a time zone string, scan until a character that is not
** a valid character in a zone name is found. Return a pointer to that
register const char * strp
;
while ((c
= *strp
) != '\0' && !isdigit(c
) && c
!= ',' && c
!= '-' &&
** Given a pointer into a time zone string, extract a number from that string.
** Check that the number is within a specified range; if it is not, return
** Otherwise, return a pointer to the first character not part of the number.
getnum(strp
, nump
, min
, max
)
register const char * strp
;
if (strp
== NULL
|| !isdigit(*strp
))
while ((c
= *strp
) != '\0' && isdigit(c
)) {
num
= num
* 10 + (c
- '0');
return NULL
; /* illegal value */
return NULL
; /* illegal value */
** Given a pointer into a time zone string, extract a number of seconds,
** in hh[:mm[:ss]] form, from the string.
** If any error occurs, return NULL.
** Otherwise, return a pointer to the first character not part of the number
register const char * strp
;
strp
= getnum(strp
, &num
, 0, HOURSPERDAY
);
*secsp
= num
* SECSPERHOUR
;
strp
= getnum(strp
, &num
, 0, MINSPERHOUR
- 1);
*secsp
+= num
* SECSPERMIN
;
strp
= getnum(strp
, &num
, 0, SECSPERMIN
- 1);
** Given a pointer into a time zone string, extract an offset, in
** [+-]hh[:mm[:ss]] form, from the string.
** If any error occurs, return NULL.
** Otherwise, return a pointer to the first character not part of the time.
register const char * strp
;
} else if (isdigit(*strp
) || *strp
++ == '+')
else return NULL
; /* illegal offset */
strp
= getsecs(strp
, offsetp
);
return NULL
; /* illegal time */
** Given a pointer into a time zone string, extract a rule in the form
** date[/time]. See POSIX section 8 for the format of "date" and "time".
** If a valid rule is not found, return NULL.
** Otherwise, return a pointer to the first character not part of the rule.
register struct rule
* const rulep
;
rulep
->r_type
= JULIAN_DAY
;
strp
= getnum(strp
, &rulep
->r_day
, 1, DAYSPERNYEAR
);
} else if (*strp
== 'M') {
rulep
->r_type
= MONTH_NTH_DAY_OF_WEEK
;
strp
= getnum(strp
, &rulep
->r_mon
, 1, MONSPERYEAR
);
strp
= getnum(strp
, &rulep
->r_week
, 1, 5);
strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERWEEK
- 1);
} else if (isdigit(*strp
)) {
rulep
->r_type
= DAY_OF_YEAR
;
strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERLYEAR
- 1);
} else return NULL
; /* invalid format */
strp
= getsecs(strp
, &rulep
->r_time
);
} else rulep
->r_time
= 2 * SECSPERHOUR
; /* default = 2:00:00 */
** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
** year, a rule, and the offset from GMT at the time that rule takes effect,
** calculate the Epoch-relative time that rule takes effect.
transtime(janfirst
, year
, rulep
, offset
)
register const struct rule
* const rulep
;
int d
, m1
, yy0
, yy1
, yy2
, dow
;
** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
** In non-leap years, or if the day number is 59 or less, just
** add SECSPERDAY times the day number-1 to the time of
** January 1, midnight, to get the day.
value
= janfirst
+ (rulep
->r_day
- 1) * SECSPERDAY
;
if (leapyear
&& rulep
->r_day
>= 60)
** Just add SECSPERDAY times the day number to the time of
** January 1, midnight, to get the day.
value
= janfirst
+ rulep
->r_day
* SECSPERDAY
;
case MONTH_NTH_DAY_OF_WEEK
:
** Mm.n.d - nth "dth day" of month m.
for (i
= 0; i
< rulep
->r_mon
- 1; ++i
)
value
+= mon_lengths
[leapyear
][i
] * SECSPERDAY
;
** Use Zeller's Congruence to get day-of-week of first day of
m1
= (rulep
->r_mon
+ 9) % 12 + 1;
yy0
= (rulep
->r_mon
<= 2) ? (year
- 1) : year
;
dow
= ((26 * m1
- 2) / 10 +
1 + yy2
+ yy2
/ 4 + yy1
/ 4 - 2 * yy1
) % 7;
** "dow" is the day-of-week of the first day of the month. Get
** the day-of-month (zero-origin) of the first "dow" day of the
for (i
= 1; i
< rulep
->r_week
; ++i
) {
mon_lengths
[leapyear
][rulep
->r_mon
- 1])
** "d" is the day-of-month (zero-origin) of the day we want.
** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
** question. To get the Epoch-relative time of the specified local
** time on that day, add the transition time and the current offset
return value
+ rulep
->r_time
+ offset
;
** Given a POSIX section 8-style TZ string, fill in the rule tables as
tzparse(name
, sp
, lastditch
)
register struct state
* const sp
;
register unsigned char * typep
;
register int load_result
;
stdlen
= strlen(name
); /* length of standard zone name */
if (stdlen
>= sizeof sp
->chars
)
stdlen
= (sizeof sp
->chars
) - 1;
name
= getoffset(name
, &stdoffset
);
load_result
= tzload(TZDEFRULES
, sp
);
sp
->leapcnt
= 0; /* so, we're off a little */
dstlen
= name
- dstname
; /* length of DST zone name */
if (*name
!= '\0' && *name
!= ',' && *name
!= ';') {
name
= getoffset(name
, &dstoffset
);
} else dstoffset
= stdoffset
- SECSPERHOUR
;
if (*name
== ',' || *name
== ';') {
register time_t janfirst
;
if ((name
= getrule(name
, &start
)) == NULL
)
if ((name
= getrule(name
, &end
)) == NULL
)
sp
->typecnt
= 2; /* standard time and DST */
** Two transitions per year, from EPOCH_YEAR to 2037.
sp
->timecnt
= 2 * (2037 - EPOCH_YEAR
+ 1);
if (sp
->timecnt
> TZ_MAX_TIMES
)
sp
->ttis
[0].tt_gmtoff
= -dstoffset
;
sp
->ttis
[0].tt_isdst
= 1;
sp
->ttis
[0].tt_abbrind
= stdlen
+ 1;
sp
->ttis
[1].tt_gmtoff
= -stdoffset
;
sp
->ttis
[1].tt_isdst
= 0;
sp
->ttis
[1].tt_abbrind
= 0;
for (year
= EPOCH_YEAR
; year
<= 2037; ++year
) {
starttime
= transtime(janfirst
, year
, &start
,
endtime
= transtime(janfirst
, year
, &end
,
if (starttime
> endtime
) {
*typep
++ = 1; /* DST ends */
*typep
++ = 0; /* DST begins */
*typep
++ = 0; /* DST begins */
*typep
++ = 1; /* DST ends */
year_lengths
[isleap(year
)] * SECSPERDAY
;
** Compute the difference between the real and
** prototype standard and summer time offsets
** from GMT, and put the real standard and summer
** time offsets into the rules in place of the
for (i
= 0; i
< sp
->typecnt
; ++i
) {
if (sp
->ttis
[i
].tt_isdst
) {
sp
->ttis
[i
].tt_gmtoff
+ dstoffset
;
if (sawdst
&& (oldfix
!= dstfix
))
sp
->ttis
[i
].tt_gmtoff
= -dstoffset
;
sp
->ttis
[i
].tt_abbrind
= stdlen
+ 1;
sp
->ttis
[i
].tt_gmtoff
+ stdoffset
;
if (sawstd
&& (oldfix
!= stdfix
))
sp
->ttis
[i
].tt_gmtoff
= -stdoffset
;
sp
->ttis
[i
].tt_abbrind
= 0;
** Make sure we have both standard and summer time.
** Now correct the transition times by shifting
** them by the difference between the real and
** prototype offsets. Note that this difference
** can be different in standard and summer time;
** the prototype probably has a 1-hour difference
** between standard and summer time, but a different
** difference can be specified in TZ.
isdst
= FALSE
; /* we start in standard time */
for (i
= 0; i
< sp
->timecnt
; ++i
) {
register const struct ttinfo
* ttisp
;
** If summer time is in effect, and the
** transition time was not specified as
** standard time, add the summer time
** offset to the transition time;
** otherwise, add the standard time offset
** to the transition time.
ttisp
= &sp
->ttis
[sp
->types
[i
]];
(isdst
&& !ttisp
->tt_ttisstd
) ?
sp
->typecnt
= 1; /* only standard time */
sp
->ttis
[0].tt_gmtoff
= -stdoffset
;
sp
->ttis
[0].tt_isdst
= 0;
sp
->ttis
[0].tt_abbrind
= 0;
sp
->charcnt
= stdlen
+ 1;
sp
->charcnt
+= dstlen
+ 1;
if (sp
->charcnt
> sizeof sp
->chars
)
(void) strncpy(cp
, stdname
, stdlen
);
(void) strncpy(cp
, dstname
, dstlen
);
if (tzload(GMT
, sp
) != 0)
(void) tzparse(GMT
, sp
, TRUE
);
register const char * name
;
lclptr
= (struct state
*) malloc(sizeof *lclptr
);
settzname(); /* all we can do */
#endif /* defined ALL_STATE */
** User wants it fast rather than right.
lclptr
->leapcnt
= 0; /* so, we're off a little */
lclptr
->ttis
[0].tt_gmtoff
= 0;
lclptr
->ttis
[0].tt_abbrind
= 0;
(void) strcpy(lclptr
->chars
, GMT
);
} else if (tzload(name
, lclptr
) != 0)
if (name
[0] == ':' || tzparse(name
, lclptr
, FALSE
) != 0)
lclptr
= (struct state
*) malloc(sizeof *lclptr
);
settzname(); /* all we can do */
#endif /* defined ALL_STATE */
if (tzload((char *) NULL
, lclptr
) != 0)
** The easy way to behave "as if no library function calls" localtime
** is to not call it--so we drop its guts into "localsub", which can be
** freely called. (And no, the PANS doesn't require the above behavior--
** but it *is* desirable.)
** The unused offset argument is for the benefit of mktime variants.
localsub(timep
, offset
, tmp
)
const time_t * const timep
;
register const struct state
* sp
;
register const struct ttinfo
* ttisp
;
gmtsub(timep
, offset
, tmp
);
#endif /* defined ALL_STATE */
if (sp
->timecnt
== 0 || t
< sp
->ats
[0]) {
while (sp
->ttis
[i
].tt_isdst
)
if (++i
>= sp
->typecnt
) {
for (i
= 1; i
< sp
->timecnt
; ++i
)
** To get (wrong) behavior that's compatible with System V Release 2.0
** you'd replace the statement below with
** t += ttisp->tt_gmtoff;
** timesub(&t, 0L, sp, tmp);
timesub(&t
, ttisp
->tt_gmtoff
, sp
, tmp
);
tmp
->tm_isdst
= ttisp
->tt_isdst
;
tzname
[tmp
->tm_isdst
] = (char *) &sp
->chars
[ttisp
->tt_abbrind
];
tmp
->tm_zone
= &sp
->chars
[ttisp
->tt_abbrind
];
const time_t * const timep
;
localsub(timep
, 0L, &tm
);
** gmtsub is to gmtime as localsub is to localtime.
gmtsub(timep
, offset
, tmp
)
const time_t * const timep
;
gmtptr
= (struct state
*) malloc(sizeof *gmtptr
);
#endif /* defined ALL_STATE */
timesub(timep
, offset
, gmtptr
, tmp
);
** Could get fancy here and deliver something such as
** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
** but this is no time for a treasure hunt.
else tmp
->TM_ZONE
= gmtptr
->chars
;
#endif /* defined ALL_STATE */
tmp
->tm_zone
= gmtptr
->chars
;
const time_t * const timep
;
timesub(timep
, offset
, sp
, tmp
)
const time_t * const timep
;
register const struct state
* const sp
;
register struct tm
* const tmp
;
register const struct lsinfo
* lp
;
i
= (sp
== NULL
) ? 0 : sp
->leapcnt
;
#endif /* defined ALL_STATE */
if (*timep
>= lp
->ls_trans
) {
if (*timep
== lp
->ls_trans
)
hit
= ((i
== 0 && lp
->ls_corr
> 0) ||
lp
->ls_corr
> sp
->lsis
[i
- 1].ls_corr
);
days
= *timep
/ SECSPERDAY
;
rem
= *timep
% SECSPERDAY
;
if (*timep
== 0x80000000) {
** A 3B1 muffs the division on the most negative number.
while (rem
>= SECSPERDAY
) {
tmp
->tm_hour
= (int) (rem
/ SECSPERHOUR
);
tmp
->tm_min
= (int) (rem
/ SECSPERMIN
);
tmp
->tm_sec
= (int) (rem
% SECSPERMIN
);
** A positive leap second requires a special
** representation. This uses "... ??:59:60".
tmp
->tm_wday
= (int) ((EPOCH_WDAY
+ days
) % DAYSPERWEEK
);
tmp
->tm_wday
+= DAYSPERWEEK
;
if (days
< (long) year_lengths
[yleap
])
days
= days
- (long) year_lengths
[yleap
];
days
= days
+ (long) year_lengths
[yleap
];
tmp
->tm_year
= y
- TM_YEAR_BASE
;
tmp
->tm_yday
= (int) days
;
for (tmp
->tm_mon
= 0; days
>= (long) ip
[tmp
->tm_mon
]; ++(tmp
->tm_mon
))
days
= days
- (long) ip
[tmp
->tm_mon
];
tmp
->tm_mday
= (int) (days
+ 1);
register const struct tm
* timeptr
;
static const char wday_name
[DAYSPERWEEK
][3] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
static const char mon_name
[MONSPERYEAR
][3] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
(void) sprintf(result
, "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n",
wday_name
[timeptr
->tm_wday
],
mon_name
[timeptr
->tm_mon
],
timeptr
->tm_mday
, timeptr
->tm_hour
,
timeptr
->tm_min
, timeptr
->tm_sec
,
TM_YEAR_BASE
+ timeptr
->tm_year
);
const time_t * const timep
;
return asctime(localtime(timep
));
** Adapted from code provided by Robert Elz, who writes:
** The "best" way to do mktime I think is based on an idea of Bob
** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
** It does a binary search of the time_t space. Since time_t's are
** just 32 bits, its a max of 32 iterations (even at 64 bits it
** would still be very reasonable).
#endif /* !defined WRONG */
normalize(tensptr
, unitsptr
, base
)
*tensptr
+= *unitsptr
/ base
;
} else if (*unitsptr
< 0) {
*tensptr
-= 1 + (-*unitsptr
) / base
;
*unitsptr
= base
- (-*unitsptr
) % base
;
register const struct tm
* const atmp
;
register const struct tm
* const btmp
;
if ((result
= (atmp
->tm_year
- btmp
->tm_year
)) == 0 &&
(result
= (atmp
->tm_mon
- btmp
->tm_mon
)) == 0 &&
(result
= (atmp
->tm_mday
- btmp
->tm_mday
)) == 0 &&
(result
= (atmp
->tm_hour
- btmp
->tm_hour
)) == 0 &&
(result
= (atmp
->tm_min
- btmp
->tm_min
)) == 0)
result
= atmp
->tm_sec
- btmp
->tm_sec
;
time2(tmp
, funcp
, offset
, okayp
)
register const struct state
* sp
;
register int saved_seconds
;
if (yourtm
.tm_sec
>= SECSPERMIN
+ 2 || yourtm
.tm_sec
< 0)
normalize(&yourtm
.tm_min
, &yourtm
.tm_sec
, SECSPERMIN
);
normalize(&yourtm
.tm_hour
, &yourtm
.tm_min
, MINSPERHOUR
);
normalize(&yourtm
.tm_mday
, &yourtm
.tm_hour
, HOURSPERDAY
);
normalize(&yourtm
.tm_year
, &yourtm
.tm_mon
, MONSPERYEAR
);
while (yourtm
.tm_mday
<= 0) {
year_lengths
[isleap(yourtm
.tm_year
+ TM_YEAR_BASE
)];
i
= mon_lengths
[isleap(yourtm
.tm_year
+
TM_YEAR_BASE
)][yourtm
.tm_mon
];
if (++yourtm
.tm_mon
>= MONSPERYEAR
) {
saved_seconds
= yourtm
.tm_sec
;
** Calculate the number of magnitude bits in a time_t
** (this works regardless of whether time_t is
** signed or unsigned, though lint complains if unsigned).
for (bits
= 0, t
= 1; t
> 0; ++bits
, t
<<= 1)
** If time_t is signed, then 0 is the median value,
** if time_t is unsigned, then 1 << bits is median.
t
= (t
< 0) ? 0 : ((time_t) 1 << bits
);
(*funcp
)(&t
, offset
, &mytm
);
dir
= tmcomp(&mytm
, &yourtm
);
else t
+= (time_t) 1 << bits
;
if (yourtm
.tm_isdst
< 0 || mytm
.tm_isdst
== yourtm
.tm_isdst
)
** Right time, wrong type.
** Hunt for right time, right type.
** It's okay to guess wrong since the guess
sp
= (const struct state
*)
((funcp
== localsub
) ? lclptr
: gmtptr
);
#endif /* defined ALL_STATE */
for (i
= 0; i
< sp
->typecnt
; ++i
) {
if (sp
->ttis
[i
].tt_isdst
!= yourtm
.tm_isdst
)
for (j
= 0; j
< sp
->typecnt
; ++j
) {
if (sp
->ttis
[j
].tt_isdst
== yourtm
.tm_isdst
)
newt
= t
+ sp
->ttis
[j
].tt_gmtoff
-
(*funcp
)(&newt
, offset
, &mytm
);
if (tmcomp(&mytm
, &yourtm
) != 0)
if (mytm
.tm_isdst
!= yourtm
.tm_isdst
)
(*funcp
)(&t
, offset
, tmp
);
time1(tmp
, funcp
, offset
)
register const struct state
* sp
;
register int samei
, otheri
;
t
= time2(tmp
, funcp
, offset
, &okay
);
if (okay
|| tmp
->tm_isdst
< 0)
** We're supposed to assume that somebody took a time of one type
** and did some math on it that yielded a "struct tm" that's bad.
** We try to divine the type they started from and adjust to the
sp
= (const struct state
*) ((funcp
== localsub
) ? lclptr
: gmtptr
);
#endif /* defined ALL_STATE */
for (samei
= 0; samei
< sp
->typecnt
; ++samei
) {
if (sp
->ttis
[samei
].tt_isdst
!= tmp
->tm_isdst
)
for (otheri
= 0; otheri
< sp
->typecnt
; ++otheri
) {
if (sp
->ttis
[otheri
].tt_isdst
== tmp
->tm_isdst
)
tmp
->tm_sec
+= sp
->ttis
[otheri
].tt_gmtoff
-
sp
->ttis
[samei
].tt_gmtoff
;
tmp
->tm_isdst
= !tmp
->tm_isdst
;
t
= time2(tmp
, funcp
, offset
, &okay
);
tmp
->tm_sec
-= sp
->ttis
[otheri
].tt_gmtoff
-
sp
->ttis
[samei
].tt_gmtoff
;
tmp
->tm_isdst
= !tmp
->tm_isdst
;
return time1(tmp
, localsub
, 0L);