1 /* 2 * mktm_r.c 3 * Original Author: Adapted from tzcode maintained by Arthur David Olson. 4 * Modifications: Changed to mktm_r and added __tzcalc_limits - 04/10/02, Jeff Johnston 5 * 6 * Converts the calendar time pointed to by tim_p into a broken-down time 7 * expressed as local time. Returns a pointer to a structure containing the 8 * broken-down time. 9 */ 10 11 #include <stdlib.h> 12 #include <time.h> 13 #include "local.h" 14 15 static _CONST int mon_lengths[2][MONSPERYEAR] = { 16 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, 17 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} 18 } ; 19 20 static _CONST int year_lengths[2] = { 21 365, 22 366 23 } ; 24 25 struct tm * 26 _DEFUN (_mktm_r, (tim_p, res, is_gmtime), 27 _CONST time_t * tim_p _AND 28 struct tm *res _AND 29 int is_gmtime) 30 { 31 long days, rem; 32 time_t lcltime; 33 int i; 34 int y; 35 int yleap; 36 _CONST int *ip; 37 38 /* base decision about std/dst time on current time */ 39 lcltime = *tim_p; 40 41 days = ((long)lcltime) / SECSPERDAY; 42 rem = ((long)lcltime) % SECSPERDAY; 43 while (rem < 0) 44 { 45 rem += SECSPERDAY; 46 --days; 47 } 48 while (rem >= SECSPERDAY) 49 { 50 rem -= SECSPERDAY; 51 ++days; 52 } 53 54 /* compute hour, min, and sec */ 55 res->tm_hour = (int) (rem / SECSPERHOUR); 56 rem %= SECSPERHOUR; 57 res->tm_min = (int) (rem / SECSPERMIN); 58 res->tm_sec = (int) (rem % SECSPERMIN); 59 60 /* compute day of week */ 61 if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0) 62 res->tm_wday += DAYSPERWEEK; 63 64 /* compute year & day of year */ 65 y = EPOCH_YEAR; 66 if (days >= 0) 67 { 68 for (;;) 69 { 70 yleap = isleap(y); 71 if (days < year_lengths[yleap]) 72 break; 73 y++; 74 days -= year_lengths[yleap]; 75 } 76 } 77 else 78 { 79 do 80 { 81 --y; 82 yleap = isleap(y); 83 days += year_lengths[yleap]; 84 } while (days < 0); 85 } 86 87 res->tm_year = y - YEAR_BASE; 88 res->tm_yday = days; 89 ip = mon_lengths[yleap]; 90 for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon) 91 days -= ip[res->tm_mon]; 92 res->tm_mday = days + 1; 93 94 if (!is_gmtime) 95 { 96 int offset; 97 int hours, mins, secs; 98 99 TZ_LOCK; 100 if (_daylight) 101 { 102 if (y == __tzyear || __tzcalc_limits (y)) 103 res->tm_isdst = (__tznorth 104 ? (*tim_p >= __tzrule[0].change && *tim_p < __tzrule[1].change) 105 : (*tim_p >= __tzrule[0].change || *tim_p < __tzrule[1].change)); 106 else 107 res->tm_isdst = -1; 108 } 109 else 110 res->tm_isdst = 0; 111 112 offset = (res->tm_isdst == 1 ? __tzrule[1].offset : __tzrule[0].offset); 113 114 hours = offset / SECSPERHOUR; 115 offset = offset % SECSPERHOUR; 116 117 mins = offset / SECSPERMIN; 118 secs = offset % SECSPERMIN; 119 120 res->tm_sec -= secs; 121 res->tm_min -= mins; 122 res->tm_hour -= hours; 123 124 if (res->tm_sec >= SECSPERMIN) 125 { 126 res->tm_min += 1; 127 res->tm_sec -= SECSPERMIN; 128 } 129 else if (res->tm_sec < 0) 130 { 131 res->tm_min -= 1; 132 res->tm_sec += SECSPERMIN; 133 } 134 if (res->tm_min >= MINSPERHOUR) 135 { 136 res->tm_hour += 1; 137 res->tm_min -= MINSPERHOUR; 138 } 139 else if (res->tm_min < 0) 140 { 141 res->tm_hour -= 1; 142 res->tm_min += MINSPERHOUR; 143 } 144 if (res->tm_hour >= HOURSPERDAY) 145 { 146 ++res->tm_yday; 147 ++res->tm_wday; 148 if (res->tm_wday > 6) 149 res->tm_wday = 0; 150 ++res->tm_mday; 151 res->tm_hour -= HOURSPERDAY; 152 if (res->tm_mday >= ip[res->tm_mon]) 153 { 154 res->tm_mday -= ip[res->tm_mon] - 1; 155 res->tm_mon += 1; 156 if (res->tm_mon == 12) 157 { 158 res->tm_mon = 0; 159 res->tm_year += 1; 160 res->tm_yday = 0; 161 } 162 } 163 } 164 else if (res->tm_hour < 0) 165 { 166 res->tm_yday -= 1; 167 res->tm_wday -= 1; 168 if (res->tm_wday < 0) 169 res->tm_wday = 6; 170 res->tm_mday -= 1; 171 res->tm_hour += 24; 172 if (res->tm_mday == 0) 173 { 174 res->tm_mon -= 1; 175 if (res->tm_mon < 0) 176 { 177 res->tm_mon = 11; 178 res->tm_year -= 1; 179 res->tm_yday = 365 + isleap(res->tm_year); 180 } 181 res->tm_mday = ip[res->tm_mon]; 182 } 183 } 184 TZ_UNLOCK; 185 } 186 else 187 res->tm_isdst = 0; 188 189 return (res); 190 } 191 192 int 193 _DEFUN (__tzcalc_limits, (year), 194 int year) 195 { 196 int days, year_days, years; 197 int i, j; 198 199 if (year < EPOCH_YEAR) 200 return 0; 201 202 __tzyear = year; 203 204 years = (year - EPOCH_YEAR); 205 206 year_days = years * 365 + 207 (years - 1 + EPOCH_YEARS_SINCE_LEAP) / 4 - (years - 1 + EPOCH_YEARS_SINCE_CENTURY) / 100 + 208 (years - 1 + EPOCH_YEARS_SINCE_LEAP_CENTURY) / 400; 209 210 for (i = 0; i < 2; ++i) 211 { 212 if (__tzrule[i].ch == 'J') 213 days = year_days + __tzrule[i].d + (isleap(year) && __tzrule[i].d >= 60); 214 else if (__tzrule[i].ch == 'D') 215 days = year_days + __tzrule[i].d; 216 else 217 { 218 int yleap = isleap(year); 219 int m_day, m_wday, wday_diff; 220 _CONST int *ip = mon_lengths[yleap]; 221 222 days = year_days; 223 224 for (j = 1; j < __tzrule[i].m; ++j) 225 days += ip[j-1]; 226 227 m_wday = (EPOCH_WDAY + days) % DAYSPERWEEK; 228 229 wday_diff = __tzrule[i].d - m_wday; 230 if (wday_diff < 0) 231 wday_diff += DAYSPERWEEK; 232 m_day = (__tzrule[i].n - 1) * DAYSPERWEEK + wday_diff; 233 234 while (m_day >= ip[j]) 235 m_day -= DAYSPERWEEK; 236 237 days += m_day; 238 } 239 240 /* store the change-over time in GMT form by adding offset */ 241 __tzrule[i].change = days * SECSPERDAY + __tzrule[i].s + __tzrule[i].offset; 242 } 243 244 __tznorth = (__tzrule[0].change < __tzrule[1].change); 245 246 return 1; 247 } 248 249