3 Copyright (c) 2007-2008 Michael G Schwern
5 This software originally derived from Paul Sheer's pivotal_gmtime_r.c.
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31 Programmers who have available to them 64-bit time values as a 'long
32 long' type can use localtime64_r() and gmtime64_r() which correctly
33 converts the time even on 32-bit systems. Whether you have 64-bit time
34 values will depend on the operating system.
36 localtime64_r() is a 64-bit equivalent of localtime_r().
38 gmtime64_r() is a 64-bit equivalent of gmtime_r().
42 static const int days_in_month[2][12] = {
43 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
44 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
47 static const int julian_days_by_month[2][12] = {
48 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
49 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335},
52 static const int length_of_year[2] = { 365, 366 };
54 /* Number of days in a 400 year Gregorian cycle */
55 static const int years_in_gregorian_cycle = 400;
56 static const int days_in_gregorian_cycle = (365 * 400) + 100 - 4 + 1;
58 /* 28 year calendar cycle between 2010 and 2037 */
59 static const int safe_years[28] = {
60 2016, 2017, 2018, 2019,
61 2020, 2021, 2022, 2023,
62 2024, 2025, 2026, 2027,
63 2028, 2029, 2030, 2031,
64 2032, 2033, 2034, 2035,
65 2036, 2037, 2010, 2011,
66 2012, 2013, 2014, 2015
69 static const int dow_year_start[28] = {
70 5, 0, 1, 2, /* 2016 - 2019 */
75 2, 4, 5, 6, /* 2036, 2037, 2010, 2011 */
76 0, 2, 3, 4 /* 2012, 2013, 2014, 2015 */
79 /* Let's assume people are going to be looking for dates in the future.
80 Let's provide some cheats so you can skip ahead.
81 This has a 4x speed boost when near 2008.
83 /* Number of days since epoch on Jan 1st, 2008 GMT */
84 #define CHEAT_DAYS (1199145600 / 24 / 60 / 60)
85 #define CHEAT_YEARS 108
87 #define IS_LEAP(n) ((!(((n) + 1900) % 400) || (!(((n) + 1900) % 4) && (((n) + 1900) % 100))) != 0)
88 #define WRAP(a,b,m) ((a) = ((a) < 0 ) ? ((b)--, (a) + (m)) : (a))
90 #define SHOULD_USE_SYSTEM_LOCALTIME(a) ( USE_SYSTEM_LOCALTIME && (a) <= SYSTEM_LOCALTIME_MAX )
91 #define SHOULD_USE_SYSTEM_GMTIME(a) ( USE_SYSTEM_GMTIME && (a) <= SYSTEM_GMTIME_MAX )
94 int _is_exception_century(Int64 year)
96 int is_exception = ((year % 100 == 0) && !(year % 400 == 0));
97 /* printf("is_exception_century: %s\n", is_exception ? "yes" : "no"); */
103 /* timegm() is a GNU extension, so emulate it here if we need it */
105 # define TIMEGM(n) timegm(n);
107 # define TIMEGM(n) _my_timegm(n);
110 time_t _my_timegm(struct tm *date) {
116 if( date->tm_year > 70 ) {
118 while( year < date->tm_year ) {
119 days += length_of_year[IS_LEAP(year)];
123 else if ( date->tm_year < 70 ) {
126 days -= length_of_year[IS_LEAP(year)];
128 } while( year >= date->tm_year );
131 days += julian_days_by_month[IS_LEAP(date->tm_year)][date->tm_mon];
132 days += date->tm_mday - 1;
134 seconds += date->tm_hour * 60 * 60;
135 seconds += date->tm_min * 60;
136 seconds += date->tm_sec;
138 time = (time_t)(days * 60 * 60 * 24) + seconds;
147 #define CHECK_TM(a) _check_tm(a);
149 void _check_tm(struct tm *tm)
151 int is_leap = IS_LEAP(tm->tm_year);
153 /* Don't forget leap seconds */
154 assert(tm->tm_sec >= 0);
155 assert(tm->tm_sec <= 61);
157 assert(tm->tm_min >= 0);
158 assert(tm->tm_min <= 59);
160 assert(tm->tm_hour >= 0);
161 assert(tm->tm_hour <= 23);
163 assert(tm->tm_mday >= 1);
164 assert(tm->tm_mday <= days_in_month[is_leap][tm->tm_mon]);
166 assert(tm->tm_mon >= 0);
167 assert(tm->tm_mon <= 11);
169 assert(tm->tm_wday >= 0);
170 assert(tm->tm_wday <= 6);
172 assert(tm->tm_yday >= 0);
173 assert(tm->tm_yday <= length_of_year[is_leap]);
175 #ifdef HAS_TM_TM_GMTOFF
176 assert(tm->tm_gmtoff >= -24 * 60 * 60);
177 assert(tm->tm_gmtoff <= 24 * 60 * 60);
183 /* The exceptional centuries without leap years cause the cycle to
186 int _cycle_offset(Int64 year)
188 const Int64 start_year = 2000;
189 Int64 year_diff = year - start_year - 1;
190 Int64 exceptions = year_diff / 100;
191 exceptions -= year_diff / 400;
193 assert( year >= 2001 );
195 /* printf("year: %d, exceptions: %d\n", year, exceptions); */
197 return exceptions * 16;
200 /* For a given year after 2038, pick the latest possible matching
201 year in the 28 year calendar cycle.
203 #define SOLAR_CYCLE_LENGTH 28
204 int _safe_year(Int64 year)
207 Int64 year_cycle = year + _cycle_offset(year);
209 /* Change non-leap xx00 years to an equivalent */
210 if( _is_exception_century(year) )
213 year_cycle %= SOLAR_CYCLE_LENGTH;
215 safe_year = safe_years[year_cycle];
217 assert(safe_year <= 2037 && safe_year >= 2010);
220 printf("year: %d, year_cycle: %d, safe_year: %d\n",
221 year, year_cycle, safe_year);
227 struct tm *gmtime64_r (const Time64_T *in_time, struct tm *p)
229 int v_tm_sec, v_tm_min, v_tm_hour, v_tm_mon, v_tm_wday;
233 Time64_T time = *in_time;
236 /* Use the system gmtime() if time_t is small enough */
237 if( SHOULD_USE_SYSTEM_GMTIME(*in_time) ) {
238 time_t safe_time = *in_time;
239 localtime_r(&safe_time, p);
244 #ifdef HAS_TM_TM_GMTOFF
249 #ifdef HAS_TM_TM_ZONE
253 v_tm_sec = time % 60;
255 v_tm_min = time % 60;
257 v_tm_hour = time % 24;
260 WRAP (v_tm_sec, v_tm_min, 60);
261 WRAP (v_tm_min, v_tm_hour, 60);
262 WRAP (v_tm_hour, v_tm_tday, 24);
263 if ((v_tm_wday = (v_tm_tday + 4) % 7) < 0)
267 if (m >= CHEAT_DAYS) {
273 /* Gregorian cycles, this is huge optimization for distant times */
274 while (m >= (Time64_T) days_in_gregorian_cycle) {
275 m -= (Time64_T) days_in_gregorian_cycle;
276 year += years_in_gregorian_cycle;
280 leap = IS_LEAP (year);
281 while (m >= (Time64_T) length_of_year[leap]) {
282 m -= (Time64_T) length_of_year[leap];
284 leap = IS_LEAP (year);
289 while (m >= (Time64_T) days_in_month[leap][v_tm_mon]) {
290 m -= (Time64_T) days_in_month[leap][v_tm_mon];
296 /* Gregorian cycles */
297 while (m < (Time64_T) -days_in_gregorian_cycle) {
298 m += (Time64_T) days_in_gregorian_cycle;
299 year -= years_in_gregorian_cycle;
303 leap = IS_LEAP (year);
304 while (m < (Time64_T) -length_of_year[leap]) {
305 m += (Time64_T) length_of_year[leap];
307 leap = IS_LEAP (year);
312 while (m < (Time64_T) -days_in_month[leap][v_tm_mon]) {
313 m += (Time64_T) days_in_month[leap][v_tm_mon];
316 m += (Time64_T) days_in_month[leap][v_tm_mon];
320 if( p->tm_year != year ) {
327 p->tm_mday = (int) m + 1;
328 p->tm_yday = julian_days_by_month[leap][v_tm_mon] + m;
329 p->tm_sec = v_tm_sec, p->tm_min = v_tm_min, p->tm_hour = v_tm_hour,
330 p->tm_mon = v_tm_mon, p->tm_wday = v_tm_wday;
338 struct tm *localtime64_r (const Time64_T *time, struct tm *local_tm)
345 /* Use the system localtime() if time_t is small enough */
346 if( SHOULD_USE_SYSTEM_LOCALTIME(*time) ) {
348 localtime_r(&safe_time, local_tm);
353 gmtime64_r(time, &gm_tm);
354 orig_year = gm_tm.tm_year;
356 if (gm_tm.tm_year > (2037 - 1900))
357 gm_tm.tm_year = _safe_year(gm_tm.tm_year + 1900) - 1900;
359 safe_time = TIMEGM(&gm_tm);
360 localtime_r(&safe_time, local_tm);
362 local_tm->tm_year = orig_year;
363 month_diff = local_tm->tm_mon - gm_tm.tm_mon;
365 /* When localtime is Dec 31st previous year and
366 gmtime is Jan 1st next year.
368 if( month_diff == 11 ) {
372 /* When localtime is Jan 1st, next year and
373 gmtime is Dec 31st, previous year.
375 if( month_diff == -11 ) {
379 /* GMT is Jan 1st, xx01 year, but localtime is still Dec 31st
380 in a non-leap xx00. There is one point in the cycle
381 we can't account for which the safe xx00 year is a leap
382 year. So we need to correct for Dec 31st comming out as
383 the 366th day of the year.
385 if( !IS_LEAP(local_tm->tm_year) && local_tm->tm_yday == 365 )