scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | README | LICENSE

mktime.c (1852B)


      1 #include <limits.h>
      2 #include <time.h>
      3 
      4 #include "../libc.h"
      5 #undef mktime
      6 
      7 static int
      8 norm(int *val, int *next, int qty)
      9 {
     10 	int v = *val, n = *next, d;
     11 
     12 	if (v < 0) {
     13 		d = -v / qty + 1;
     14 		v += d * qty;
     15 		if (n > INT_MAX - d)
     16 			return 0;
     17 		n -= d;
     18 	}
     19 	if (v >= qty) {
     20 		d = v / qty;
     21 		v -= d * qty;
     22 		if (n < INT_MIN + d)
     23 			return 0;
     24 		n += d;
     25 	}
     26 
     27 	*val = v;
     28 	*next = n;
     29 	return 1;
     30 }
     31 
     32 static int
     33 normalize(struct tm *tm)
     34 {
     35 	int mon, day, year, yday;
     36 	struct tm aux = *tm;
     37 
     38 	if (!norm(&tm->tm_sec, &tm->tm_min, 60)   ||
     39 	    !norm(&tm->tm_min, &tm->tm_hour, 60)  ||
     40 	    !norm(&tm->tm_hour, &tm->tm_mday, 24) ||
     41 	    !norm(&tm->tm_mon, &tm->tm_year, 12)) {
     42 		return 0;
     43 	}
     44 
     45 	if (tm->tm_year < 0)
     46 		return 0;
     47 
     48 	day = tm->tm_mday;
     49 	yday = 0;
     50 	year = 1900 + tm->tm_year;
     51 	_daysmon[FEB] = FEBDAYS(year);
     52 
     53 	for (mon = tm->tm_mon; day < 1; --mon) {
     54 		if (mon == JAN) {
     55 			if (year == 1900)
     56 				return 0;
     57 			year--;
     58 			_daysmon[FEB] = FEBDAYS(year);
     59 			mon = DEC+1;
     60 		}
     61 		day += _daysmon[mon-1];
     62 	}
     63 
     64 	for (; day > _daysmon[mon]; ++mon) {
     65 		day -= _daysmon[mon];
     66 		if (mon == DEC) {
     67 			if (year == _MAXYEAR)
     68 				return 0;
     69 			year++;
     70 			_daysmon[FEB] = FEBDAYS(year);
     71 			mon = JAN-1;
     72 		}
     73 	}
     74 
     75 	for (int i = 0; i < mon; i++)
     76 		yday += _daysmon[i];
     77 
     78 	tm->tm_mon = mon;
     79 	tm->tm_year = year - 1900;
     80 	tm->tm_mday = day;
     81 	tm->tm_yday = yday + day - 1;
     82 	tm->tm_wday = (_newyear(tm->tm_year) + tm->tm_yday) % 7;
     83 
     84 	return 1;
     85 }
     86 
     87 time_t
     88 mktime(struct tm *tm)
     89 {
     90 	int i, year, dst;
     91 	time_t t;
     92 	struct tm *aux;
     93 
     94 	if (!normalize(tm))
     95 		return -1;
     96 
     97 	t = 0;
     98 	year = tm->tm_year + 1900;
     99 	for (i = EPOCH; i < year; i++)
    100 		t += _daysyear(i) * SECDAY;
    101 
    102 	for (i = 0; i < tm->tm_mon; i++)
    103 		t += _daysmon[i] * SECDAY;
    104 
    105 	t += tm->tm_sec;
    106 	t += tm->tm_min * SECMIN;
    107 	t += tm->tm_hour * SECHOUR;
    108 	t += (tm->tm_mday-1) * SECDAY;
    109 
    110 	aux = localtime(&t);
    111 
    112 	t += aux->tm_gmtoff;
    113 
    114 	return t;
    115 }