3 * - By John Hodge (thePowersGang)
6 * - Shared User/Kernel time conversion code
11 #define ENABLE_LEAP_SECONDS 1
13 static const short DAYS_IN[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
14 static const short DAYS_BEFORE[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
18 #if ENABLE_LEAP_SECONDS
19 // Leap seconds after 2000 (stored as day numbers of application)
20 // - Leap seconds apply after the last second of said day (23:59:60)
21 // TODO: Need to encode possible double leap seconds, and negative leap seconds
22 static int64_t leap_seconds_after[] = {
23 // ls + (year + leap + day + thisleap)
24 (5*365+2+DEC31+0), // Dec 31 2005
25 (8*365+2+DEC31+1), // Dec 31 2008
26 (12*365+3+JUN30+1) // Jun 30 2012
28 static int n_leap_seconds_after = sizeof(leap_seconds_after)/sizeof(leap_seconds_after[0]);
31 static int YearIsLeap(int year) {
32 return (year % 4 == 0) - (year % 100 == 0) + (year % 400 == 0);
34 static int DaysUntilYear(int year) {
35 return year*365 + (year/400) - (year/100) + (year/4);
38 int64_t seconds_since_y2k(int years_since, int mon, int day, int h, int m, int s)
41 if( !(1 <= mon && mon <= 12) ) return 0;
42 if( !(1 <= day && day <= DAYS_IN[mon-1]) ) return 0;
43 if( !(0 <= h && h <= 23) ) return 0;
44 if( !(0 <= m && m <= 59) ) return 0;
45 if( !(0 <= s && s <= 60) ) return 0;
47 // Special case check for leap days
48 if( mon == 2 && day == 29 )
50 if( !YearIsLeap(years_since) )
55 int64_t days = DaysUntilYear(years_since);
56 days += DAYS_BEFORE[mon-1];
57 if(mon > 2 && YearIsLeap(years_since))
62 int64_t seconds = h * 60*60 + m * 60;
64 bool today_has_ls = false;
65 #if ENABLE_LEAP_SECONDS
68 for( int i = 0; i < n_leap_seconds_after; i ++ )
70 if( days < leap_seconds_after[i] )
72 if(days > leap_seconds_after[i])
76 // A leap second on this day is handled with s=60
80 // Now that we know if this day has a leap second, sanity check leap seconds
83 if( !today_has_ls || !(h == 23 && m == 59) )
87 if( s == 60 ) return 0;
92 return days * 24*60*60 + seconds;
95 // returns number of days
96 int64_t get_days_since_y2k(int64_t ts, int *h, int *m, int *s)
98 #if ENABLE_LEAP_SECONDS
99 // Calculate leap second count
104 for( int i = 0; i < n_leap_seconds_after; i ++ )
106 // lts = Timestamp of the leap second
107 int64_t lts = leap_seconds_after[i] * 24*60*60 + 23*60*60 + 59*60 + 60 + i;
108 if( lts > ts ) break;
117 int64_t days = ts / 24*60*60;
118 int64_t seconds = ts % (24*60*60);
119 *s = (is_ls ? 60 : seconds % 60);
120 *m = (seconds/60 % 24);
121 *h = seconds / (60*60);
127 * \param days Days since 1 Jan 2000
129 int64_t get_years_since_y2k(int64_t days, bool *is_leap, int *doy)
133 // Year (400 yr blocks) - (400/4-3) leap years
134 const int days_per_400_yrs = 365*400 + (400/4-3);
135 int year = 400 * days / days_per_400_yrs;
136 days = days % days_per_400_yrs;
137 if( days < 366 ) // First year in 400 is a leap
141 // 100 yr blocks - 100/4-1 leap years
142 const int days_per_100_yrs = 365*100 + (100/4-1);
143 year += 100 * days / days_per_100_yrs;
144 days = days % days_per_100_yrs;
145 if( days < 366 ) // First year in 100 isn't a leap
149 const int days_per_4_yrs = 365*4 + 1;
150 year += 4 * days / days_per_4_yrs;
151 days = days % days_per_4_yrs;
152 if( days < 366 ) // First year in 4 is a leap
166 void get_month_day(int doy, bool is_ly, int *mon, int *day)
168 if( doy > 365+(is_ly?1:0) ) {
173 bool mon_day_set = false;
174 if( doy >= DAYS_BEFORE[2] && is_ly )
176 if( doy == DAYS_BEFORE[2] ) {
183 for( int i = 1; i < 12+1 && !mon_day_set; i ++ )
185 if( doy < DAYS_BEFORE[i] )
188 *day = doy - DAYS_BEFORE[i];
194 int expand_from_secs_since_y2k(int64_t ts, int *years_since, int *mon, int *day, int *h, int *m, int *s)
196 int64_t days = get_days_since_y2k(ts, h, m, s);
200 *years_since = get_years_since_y2k(days, &is_ly, &doy);
202 // Calculate month/day of month
203 get_month_day(doy, is_ly, mon, day);