/* * qmktime - convert a split-out date (struct tm) back into a time_t [ANSI] */ #include #include #include #define EPOCH 1970 #define DAYS_PER_400YRS (time_t)146097 #define DAYS_PER_4YRS (time_t)1461 #define DIVBY4(n) ((n) >> 2) #define YRNUM(c, y) (DIVBY4(DAYS_PER_400YRS*(c)) + DIVBY4(DAYS_PER_4YRS*(y))) #define DAYNUM(c,y,mon,d) (YRNUM((c), (y)) + mdays[mon] + (d)) #define EPOCH_DAYNUM DAYNUM(19, 69, 10, 1) /* really January 1, 1970 */ static char nmdays[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; /* days since start of year. mdays[0] is March, mdays[11] is February */ static short mdays[] = { 0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337 }; /* * near-ANSI qmktime suitable for use by dateconv; not necessarily as paranoid * as ANSI requires, and it may not canonicalise the struct tm. Ignores tm_wday * and tm_yday. */ time_t qmktime(tp) register struct tm *tp; { register int mon = tp->tm_mon + 1; /* convert to 1-origin */ register int day = tp->tm_mday, year = tp->tm_year + 1900; register time_t daynum; register int century; time_t nrdaynum; if (year < EPOCH) return -1; /* can't represent early date */ /* * validate day against days-per-month table, with leap-year * correction */ if (day > nmdays[mon]) if (mon != 2 || year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) && day > 29) return -1; /* day too large for month */ /* split year into century and year-of-century */ century = year / 100; year %= 100; /* * We calculate the day number exactly, assuming the calendar has * always had the current leap year rules. (The leap year rules are * to compensate for the fact that the Earth's revolution around the * Sun takes 365.2425 days). We first need to rotate months so March * is 0, since we want the last month to have the reduced number of * days. */ if (mon > 2) mon -= 3; else { mon += 9; if (year == 0) { century--; year = 99; } else --year; } daynum = -EPOCH_DAYNUM + DAYNUM(century, year, mon, day); /* convert to seconds */ nrdaynum = daynum = tp->tm_sec + (tp->tm_min +(daynum*24 + tp->tm_hour)*60)*60; /* daylight correction */ if (tp->tm_isdst < 0) /* unknown; find out */ tp->tm_isdst = localtime(&nrdaynum)->tm_isdst; if (tp->tm_isdst > 0) daynum -= 60*60; return daynum < 0? -1: daynum; }