Rich Felker | 0b44a03 | 2011-02-12 00:22:29 -0500 | [diff] [blame] | 1 | #include <time.h> |
| 2 | |
| 3 | /* C defines the rounding for division in a nonsensical way */ |
| 4 | #define Q(a,b) ((a)>0 ? (a)/(b) : -(((b)-(a)-1)/(b))) |
| 5 | |
| 6 | #define DAYS_PER_400Y (365*400 + 97) |
| 7 | #define DAYS_PER_100Y (365*100 + 24) |
| 8 | #define DAYS_PER_4Y (365*4 + 1) |
| 9 | |
| 10 | /* FIXME: use lldiv once it's fixed to compute quot,rem together */ |
| 11 | struct tm *__time_to_tm(time_t t, struct tm *tm) |
| 12 | { |
| 13 | /* months are march-based */ |
| 14 | static const int days_thru_month[] = {31,61,92,122,153,184,214,245,275,306,337,366}; |
| 15 | long long bigday; |
| 16 | unsigned int day, year4, year100; |
| 17 | int year, year400; |
| 18 | int month; |
| 19 | int leap; |
| 20 | int hour, min, sec; |
| 21 | int wday, mday, yday; |
| 22 | |
| 23 | /* start from 2000-03-01 (multiple of 400 years) */ |
| 24 | t += -946684800 - 86400*(31+29); |
| 25 | |
| 26 | bigday = Q(t, 86400); |
| 27 | sec = t-bigday*86400; |
| 28 | |
| 29 | hour = sec/3600; |
| 30 | sec -= hour*3600; |
| 31 | min = sec/60; |
| 32 | sec -= min*60; |
| 33 | |
| 34 | /* 2000-03-01 was a wednesday */ |
| 35 | wday = (3+bigday)%7; |
| 36 | if (wday < 0) wday += 7; |
| 37 | |
| 38 | t = -946684800LL - 86400*(31+29) + 9000000; |
| 39 | |
| 40 | year400 = Q(bigday, DAYS_PER_400Y); |
| 41 | day = bigday-year400*DAYS_PER_400Y; |
| 42 | |
| 43 | year100 = day/DAYS_PER_100Y; |
| 44 | if (year100 == 4) year100--; |
| 45 | day -= year100*DAYS_PER_100Y; |
| 46 | |
| 47 | year4 = day/DAYS_PER_4Y; |
| 48 | if (year4 == 25) year4--; |
| 49 | day -= year4*DAYS_PER_4Y; |
| 50 | |
| 51 | year = day/365; |
| 52 | if (year == 4) year--; |
| 53 | day -= year*365; |
| 54 | |
| 55 | leap = !year && (year4 || !year100); |
| 56 | yday = day + 31+28 + leap; |
| 57 | if (yday >= 365+leap) yday -= 365+leap; |
| 58 | |
| 59 | year += 4*year4 + 100*year100 + 400*year400 + 2000-1900; |
| 60 | |
| 61 | for (month=0; days_thru_month[month] <= day; month++); |
| 62 | if (month) day -= days_thru_month[month-1]; |
| 63 | month += 2; |
| 64 | if (month >= 12) { |
| 65 | month -= 12; |
| 66 | year++; |
| 67 | } |
| 68 | |
| 69 | mday = day+1; |
| 70 | |
| 71 | tm->tm_sec = sec; |
| 72 | tm->tm_min = min; |
| 73 | tm->tm_hour= hour; |
| 74 | tm->tm_mday= mday; |
| 75 | tm->tm_mon = month; |
| 76 | tm->tm_year= year; |
| 77 | tm->tm_wday= wday; |
| 78 | tm->tm_yday= yday; |
| 79 | |
| 80 | return tm; |
| 81 | } |