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