__secs_to_tm.c raw

   1  #include "time_impl.h"
   2  #include <limits.h>
   3  
   4  /* 2000-03-01 (mod 400 year, immediately after feb29 */
   5  #define LEAPOCH (946684800LL + 86400*(31+29))
   6  
   7  #define DAYS_PER_400Y (365*400 + 97)
   8  #define DAYS_PER_100Y (365*100 + 24)
   9  #define DAYS_PER_4Y   (365*4   + 1)
  10  
  11  int __secs_to_tm(long long t, struct tm *tm)
  12  {
  13  	long long days, secs, years;
  14  	int remdays, remsecs, remyears;
  15  	int qc_cycles, c_cycles, q_cycles;
  16  	int months;
  17  	int wday, yday, leap;
  18  	static const char days_in_month[] = {31,30,31,30,31,31,30,31,30,31,31,29};
  19  
  20  	/* Reject time_t values whose year would overflow int */
  21  	if (t < INT_MIN * 31622400LL || t > INT_MAX * 31622400LL)
  22  		return -1;
  23  
  24  	secs = t - LEAPOCH;
  25  	days = secs / 86400;
  26  	remsecs = secs % 86400;
  27  	if (remsecs < 0) {
  28  		remsecs += 86400;
  29  		days--;
  30  	}
  31  
  32  	wday = (3+days)%7;
  33  	if (wday < 0) wday += 7;
  34  
  35  	qc_cycles = days / DAYS_PER_400Y;
  36  	remdays = days % DAYS_PER_400Y;
  37  	if (remdays < 0) {
  38  		remdays += DAYS_PER_400Y;
  39  		qc_cycles--;
  40  	}
  41  
  42  	c_cycles = remdays / DAYS_PER_100Y;
  43  	if (c_cycles == 4) c_cycles--;
  44  	remdays -= c_cycles * DAYS_PER_100Y;
  45  
  46  	q_cycles = remdays / DAYS_PER_4Y;
  47  	if (q_cycles == 25) q_cycles--;
  48  	remdays -= q_cycles * DAYS_PER_4Y;
  49  
  50  	remyears = remdays / 365;
  51  	if (remyears == 4) remyears--;
  52  	remdays -= remyears * 365;
  53  
  54  	leap = !remyears && (q_cycles || !c_cycles);
  55  	yday = remdays + 31 + 28 + leap;
  56  	if (yday >= 365+leap) yday -= 365+leap;
  57  
  58  	years = remyears + 4*q_cycles + 100*c_cycles + 400LL*qc_cycles;
  59  
  60  	for (months=0; days_in_month[months] <= remdays; months++)
  61  		remdays -= days_in_month[months];
  62  
  63  	if (months >= 10) {
  64  		months -= 12;
  65  		years++;
  66  	}
  67  
  68  	if (years+100 > INT_MAX || years+100 < INT_MIN)
  69  		return -1;
  70  
  71  	tm->tm_year = years + 100;
  72  	tm->tm_mon = months + 2;
  73  	tm->tm_mday = remdays + 1;
  74  	tm->tm_wday = wday;
  75  	tm->tm_yday = yday;
  76  
  77  	tm->tm_hour = remsecs / 3600;
  78  	tm->tm_min = remsecs / 60 % 60;
  79  	tm->tm_sec = remsecs % 60;
  80  
  81  	return 0;
  82  }
  83