mktime.c - scc - simple c99 compiler
(HTM) git clone git://git.simple-cc.org/scc
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) Submodules
(DIR) README
(DIR) LICENSE
---
mktime.c (1886B)
---
1 #include <limits.h>
2 #include <time.h>
3
4 #include "../libc.h"
5
6 #undef mktime
7
8 static int
9 norm(int *val, int *next, int max)
10 {
11 int v = *val, n = *next, d;
12
13 if (v < 0) {
14 d = -v / max + 1;
15 v += d * max;
16 if (n > INT_MAX - d)
17 return 0;
18 n -= d;
19 }
20 if (v >= max) {
21 d = v / max;
22 v -= d * max;
23 if (n < INT_MIN + d)
24 return 0;
25 n += d;
26 }
27
28 *val = v;
29 *next = n;
30 return 1;
31 }
32
33 static int
34 normalize(struct tm *tm)
35 {
36 int mon, day, year, yday;
37
38 /*
39 * Normalize sec so that it doesn't over/underflow min
40 * Normalize min so that it doesn't over/underflow hour
41 * Normalize hour so that it doesn't over/underflow mday
42 * Normalize month so that it doesn't over/underflow year
43 */
44 if (!norm(&tm->tm_sec, &tm->tm_min, 60)
45 || !norm(&tm->tm_min, &tm->tm_hour, 60)
46 || !norm(&tm->tm_hour, &tm->tm_mday, 24)
47 || !norm(&tm->tm_mon, &tm->tm_year, 12))
48 return 0;
49
50 if (tm->tm_year < 0)
51 return 0;
52
53 day = tm->tm_mday;
54 yday = 0;
55 year = MINYEAR + tm->tm_year;
56
57 if (year > _MAXYEAR)
58 return 0;
59
60 _daysmon[FEB] = FEBDAYS(year);
61
62 /*
63 * Normalize mday so that it doesn't over/underflow month
64 * Normalize month so that it doesn't over/underflow year
65 */
66 for (mon = tm->tm_mon; day < 1; --mon) {
67 if (mon == JAN) {
68 if (year == MINYEAR)
69 return 0;
70 year--;
71 _daysmon[FEB] = FEBDAYS(year);
72 mon = DEC+1;
73 }
74 day += _daysmon[mon-1];
75 }
76
77 for (; day > _daysmon[mon]; ++mon) {
78 day -= _daysmon[mon];
79 if (mon == DEC) {
80 if (year == _MAXYEAR)
81 return 0;
82 year++;
83 _daysmon[FEB] = FEBDAYS(year);
84 mon = JAN-1;
85 }
86 }
87
88 for (int i = 0; i < mon; ++i)
89 yday += _daysmon[i];
90
91 tm->tm_mon = mon;
92 tm->tm_year = year - MINYEAR;
93 tm->tm_mday = day;
94 tm->tm_yday = yday + day - 1;
95 tm->tm_wday = (_newyear(tm->tm_year) + tm->tm_yday) % 7;
96 tm->tm_isdst = 0;
97 return 1;
98 }
99
100 time_t
101 mktime(struct tm *tm)
102 {
103 if (!normalize(tm))
104 return -1;
105 return _systime(tm);
106 }