Pristine Ack-5.5
[Ack-5.5.git] / lang / cem / libcc.ansi / time / mktime.c
1 /*
2  * mktime - convert local time into calendar time
3  */
4 /* $Id: mktime.c,v 1.6 1994/06/24 11:58:20 ceriel Exp $ */
5
6 #include        <time.h>
7 #include        <limits.h>
8 #include        "loc_time.h"
9
10 /* The code assumes that unsigned long can be converted to time_t.
11  * A time_t should not be wider than unsigned long, since this would mean
12  * that the check for overflow at the end could fail.
13  */
14 time_t
15 mktime(register struct tm *timep)
16 {
17         register long day, year;
18         register int tm_year;
19         int yday, month;
20         register unsigned long seconds;
21         int overflow;
22         unsigned dst;
23
24         timep->tm_min += timep->tm_sec / 60;
25         timep->tm_sec %= 60;
26         if (timep->tm_sec < 0) {
27                 timep->tm_sec += 60;
28                 timep->tm_min--;
29         }
30         timep->tm_hour += timep->tm_min / 60;
31         timep->tm_min = timep->tm_min % 60;
32         if (timep->tm_min < 0) {
33                 timep->tm_min += 60;
34                 timep->tm_hour--;
35         }
36         day = timep->tm_hour / 24;
37         timep->tm_hour= timep->tm_hour % 24;
38         if (timep->tm_hour < 0) {
39                 timep->tm_hour += 24;
40                 day--;
41         }
42         timep->tm_year += timep->tm_mon / 12;
43         timep->tm_mon %= 12;
44         if (timep->tm_mon < 0) {
45                 timep->tm_mon += 12;
46                 timep->tm_year--;
47         }
48         day += (timep->tm_mday - 1);
49         while (day < 0) {
50                 day += YEARSIZE(YEAR0 + timep->tm_year - 1);
51                 timep->tm_year--;
52         }
53         while (day >= YEARSIZE(YEAR0 + timep->tm_year)) {
54                 day -= YEARSIZE(YEAR0 + timep->tm_year);
55                 timep->tm_year++;
56         }
57         while (day >= _ytab[LEAPYEAR(YEAR0 + timep->tm_year)][timep->tm_mon]) {
58                 day -= _ytab[LEAPYEAR(YEAR0 + timep->tm_year)][timep->tm_mon];
59                 if (++(timep->tm_mon) == 12) {
60                         timep->tm_mon = 0;
61                         timep->tm_year++;
62                 }
63         }
64         timep->tm_mday = day + 1;
65         _tzset();                       /* set timezone and dst info  */
66         year = EPOCH_YR;
67         if (timep->tm_year < year - YEAR0) return (time_t)-1;
68         seconds = 0;
69         day = 0;                        /* means days since day 0 now */
70         overflow = 0;
71
72         /* Assume that when day becomes negative, there will certainly
73          * be overflow on seconds.
74          * The check for overflow needs not to be done for leapyears
75          * divisible by 400.
76          * The code only works when year (1970) is not a leapyear.
77          */
78 #if     EPOCH_YR != 1970
79 #error  EPOCH_YR != 1970
80 #endif
81         tm_year = timep->tm_year + YEAR0;
82
83         if (LONG_MAX / 365 < tm_year - year) overflow++;
84         day = (tm_year - year) * 365;
85         if (LONG_MAX - day < (tm_year - year) / 4 + 1) overflow++;
86         day += (tm_year - year) / 4
87                 + ((tm_year % 4) && tm_year % 4 < year % 4);
88         day -= (tm_year - year) / 100
89                 + ((tm_year % 100) && tm_year % 100 < year % 100);
90         day += (tm_year - year) / 400
91                 + ((tm_year % 400) && tm_year % 400 < year % 400);
92
93         yday = month = 0;
94         while (month < timep->tm_mon) {
95                 yday += _ytab[LEAPYEAR(tm_year)][month];
96                 month++;
97         }
98         yday += (timep->tm_mday - 1);
99         if (day + yday < 0) overflow++;
100         day += yday;
101
102         timep->tm_yday = yday;
103         timep->tm_wday = (day + 4) % 7;         /* day 0 was thursday (4) */
104
105         seconds = ((timep->tm_hour * 60L) + timep->tm_min) * 60L + timep->tm_sec;
106
107         if ((TIME_MAX - seconds) / SECS_DAY < day) overflow++;
108         seconds += day * SECS_DAY;
109
110         /* Now adjust according to timezone and daylight saving time */
111
112         if (((_timezone > 0) && (TIME_MAX - _timezone < seconds))
113             || ((_timezone < 0) && (seconds < -_timezone)))
114                 overflow++;
115         seconds += _timezone;
116
117         if (timep->tm_isdst < 0)
118                 dst = _dstget(timep);
119         else if (timep->tm_isdst)
120                 dst = _dst_off;
121         else dst = 0;
122
123         if (dst > seconds) overflow++;  /* dst is always non-negative */
124         seconds -= dst;
125
126         if (overflow) return (time_t)-1;
127
128         if ((time_t)seconds != seconds) return (time_t)-1;
129         return (time_t)seconds;
130 }