scc

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

mktime.c (1867B)


      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;
     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 	day = tm->tm_mday;
     46 	year = EPOCH + tm->tm_year;
     47 	_daysmon[FEB] = FEBDAYS(year);
     48 
     49 	for (mon = tm->tm_mon; day < 1; --mon) {
     50 		day += _daysmon[mon];
     51 		if (mon == JAN) {
     52 			if (year == EPOCH)
     53 				return -1;
     54 			year--;
     55 			_daysmon[FEB] = FEBDAYS(year);
     56 			mon = DEC+1;
     57 		}
     58 	}
     59 
     60 	for (; day > _daysmon[mon]; ++mon) {
     61 		day -= _daysmon[mon];
     62 		if (mon == DEC) {
     63 			if (year == _MAXYEAR)
     64 				return -1;
     65 			year++;
     66 			_daysmon[FEB] = FEBDAYS(year);
     67 			mon = JAN-1;
     68 		}
     69 	}
     70 
     71 	tm->tm_mon = mon;
     72 	tm->tm_year = year - EPOCH;
     73 	tm->tm_mday = day;
     74 	tm->tm_wday = (_newyear(tm->tm_year) + tm->tm_yday) % 7;
     75 
     76 	return 1;
     77 }
     78 
     79 time_t
     80 mktime(struct tm *tm)
     81 {
     82 	int i, year, dst;
     83 	time_t t;
     84 	struct tm *aux;
     85 
     86 	if (!normalize(tm))
     87 		return -1;
     88 
     89 	t = 0;
     90 	year = tm->tm_year + 1900;
     91 	for (i = EPOCH; i < year; i++)
     92 		t += _daysyear(i) * SECDAY;
     93 
     94 	for (i = 0; i < tm->tm_mon; i++)
     95 		t += _daysmon[i] * SECDAY;
     96 
     97 	t += tm->tm_sec;
     98 	t += tm->tm_min * SECMIN;
     99 	t += tm->tm_hour * SECHOUR;
    100 	t += (tm->tm_mday-1) * SECDAY;
    101 
    102 	aux = localtime(&t);
    103 
    104 	dst = 0;
    105 	if (tm->tm_isdst == 0 && aux->tm_isdst == 1)
    106 		dst = -SECHOUR;
    107 	else if (tm->tm_isdst == 1 && aux->tm_isdst == 0)
    108 		dst = +SECHOUR;
    109 
    110 	t += aux->tm_gmtoff + dst;
    111 
    112 	return t;
    113 }