Changeset f7ea5400 in mainline for uspace/lib/posix/time.c
- Timestamp:
- 2012-08-15T17:52:09Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 16639bb
- Parents:
- 9dec6d4
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/posix/time.c
r9dec6d4 rf7ea5400 61 61 */ 62 62 63 64 65 /* Helper functions ***********************************************************/66 67 #define HOURS_PER_DAY (24)68 #define MINS_PER_HOUR (60)69 #define SECS_PER_MIN (60)70 #define MINS_PER_DAY (MINS_PER_HOUR * HOURS_PER_DAY)71 #define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR)72 #define SECS_PER_DAY (SECS_PER_HOUR * HOURS_PER_DAY)73 74 /**75 * Checks whether the year is a leap year.76 *77 * @param year Year since 1900 (e.g. for 1970, the value is 70).78 * @return true if year is a leap year, false otherwise79 */80 static bool _is_leap_year(time_t year)81 {82 year += 1900;83 84 if (year % 400 == 0)85 return true;86 if (year % 100 == 0)87 return false;88 if (year % 4 == 0)89 return true;90 return false;91 }92 93 /**94 * Returns how many days there are in the given month of the given year.95 * Note that year is only taken into account if month is February.96 *97 * @param year Year since 1900 (can be negative).98 * @param mon Month of the year. 0 for January, 11 for December.99 * @return Number of days in the specified month.100 */101 static int _days_in_month(time_t year, time_t mon)102 {103 assert(mon >= 0 && mon <= 11);104 105 static int month_days[] =106 { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };107 108 if (mon == 1) {109 year += 1900;110 /* february */111 return _is_leap_year(year) ? 29 : 28;112 } else {113 return month_days[mon];114 }115 }116 117 /**118 * For specified year, month and day of month, returns which day of that year119 * it is.120 *121 * For example, given date 2011-01-03, the corresponding expression is:122 * _day_of_year(111, 0, 3) == 2123 *124 * @param year Year (year 1900 = 0, can be negative).125 * @param mon Month (January = 0).126 * @param mday Day of month (First day is 1).127 * @return Day of year (First day is 0).128 */129 static int _day_of_year(time_t year, time_t mon, time_t mday)130 {131 static int mdays[] =132 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };133 static int leap_mdays[] =134 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };135 136 return (_is_leap_year(year) ? leap_mdays[mon] : mdays[mon]) + mday - 1;137 }138 139 /**140 * Integer division that rounds to negative infinity.141 * Used by some functions in this file.142 *143 * @param op1 Dividend.144 * @param op2 Divisor.145 * @return Rounded quotient.146 */147 static time_t _floor_div(time_t op1, time_t op2)148 {149 if (op1 >= 0 || op1 % op2 == 0) {150 return op1 / op2;151 } else {152 return op1 / op2 - 1;153 }154 }155 156 /**157 * Modulo that rounds to negative infinity.158 * Used by some functions in this file.159 *160 * @param op1 Dividend.161 * @param op2 Divisor.162 * @return Remainder.163 */164 static time_t _floor_mod(time_t op1, time_t op2)165 {166 int div = _floor_div(op1, op2);167 168 /* (a / b) * b + a % b == a */169 /* thus, a % b == a - (a / b) * b */170 171 int result = op1 - div * op2;172 173 /* Some paranoid checking to ensure I didn't make a mistake here. */174 assert(result >= 0);175 assert(result < op2);176 assert(div * op2 + result == op1);177 178 return result;179 }180 181 /**182 * Number of days since the Epoch.183 * Epoch is 1970-01-01, which is also equal to day 0.184 *185 * @param year Year (year 1900 = 0, may be negative).186 * @param mon Month (January = 0).187 * @param mday Day of month (first day = 1).188 * @return Number of days since the Epoch.189 */190 static time_t _days_since_epoch(time_t year, time_t mon, time_t mday)191 {192 return (year - 70) * 365 + _floor_div(year - 69, 4) -193 _floor_div(year - 1, 100) + _floor_div(year + 299, 400) +194 _day_of_year(year, mon, mday);195 }196 197 /**198 * Which day of week the specified date is.199 *200 * @param year Year (year 1900 = 0).201 * @param mon Month (January = 0).202 * @param mday Day of month (first = 1).203 * @return Day of week (Sunday = 0).204 */205 static int _day_of_week(time_t year, time_t mon, time_t mday)206 {207 /* 1970-01-01 is Thursday */208 return _floor_mod((_days_since_epoch(year, mon, mday) + 4), 7);209 }210 211 /**212 * Normalizes the broken-down time and optionally adds specified amount of213 * seconds.214 *215 * @param tm Broken-down time to normalize.216 * @param sec_add Seconds to add.217 * @return 0 on success, -1 on overflow218 */219 static int _normalize_time(struct tm *tm, time_t sec_add)220 {221 // TODO: DST correction222 223 /* Set initial values. */224 time_t sec = tm->tm_sec + sec_add;225 time_t min = tm->tm_min;226 time_t hour = tm->tm_hour;227 time_t day = tm->tm_mday - 1;228 time_t mon = tm->tm_mon;229 time_t year = tm->tm_year;230 231 /* Adjust time. */232 min += _floor_div(sec, SECS_PER_MIN);233 sec = _floor_mod(sec, SECS_PER_MIN);234 hour += _floor_div(min, MINS_PER_HOUR);235 min = _floor_mod(min, MINS_PER_HOUR);236 day += _floor_div(hour, HOURS_PER_DAY);237 hour = _floor_mod(hour, HOURS_PER_DAY);238 239 /* Adjust month. */240 year += _floor_div(mon, 12);241 mon = _floor_mod(mon, 12);242 243 /* Now the difficult part - days of month. */244 245 /* First, deal with whole cycles of 400 years = 146097 days. */246 year += _floor_div(day, 146097) * 400;247 day = _floor_mod(day, 146097);248 249 /* Then, go in one year steps. */250 if (mon <= 1) {251 /* January and February. */252 while (day > 365) {253 day -= _is_leap_year(year) ? 366 : 365;254 year++;255 }256 } else {257 /* Rest of the year. */258 while (day > 365) {259 day -= _is_leap_year(year + 1) ? 366 : 365;260 year++;261 }262 }263 264 /* Finally, finish it off month per month. */265 while (day >= _days_in_month(year, mon)) {266 day -= _days_in_month(year, mon);267 mon++;268 if (mon >= 12) {269 mon -= 12;270 year++;271 }272 }273 274 /* Calculate the remaining two fields. */275 tm->tm_yday = _day_of_year(year, mon, day + 1);276 tm->tm_wday = _day_of_week(year, mon, day + 1);277 278 /* And put the values back to the struct. */279 tm->tm_sec = (int) sec;280 tm->tm_min = (int) min;281 tm->tm_hour = (int) hour;282 tm->tm_mday = (int) day + 1;283 tm->tm_mon = (int) mon;284 285 /* Casts to work around libc brain-damage. */286 if (year > ((int)INT_MAX) || year < ((int)INT_MIN)) {287 tm->tm_year = (year < 0) ? ((int)INT_MIN) : ((int)INT_MAX);288 return -1;289 }290 291 tm->tm_year = (int) year;292 return 0;293 }294 295 /******************************************************************************/296 297 63 int posix_daylight; 298 64 long posix_timezone; … … 321 87 struct tm *restrict result) 322 88 { 323 assert(timer != NULL); 324 assert(result != NULL); 325 326 /* Set result to epoch. */ 327 result->tm_sec = 0; 328 result->tm_min = 0; 329 result->tm_hour = 0; 330 result->tm_mday = 1; 331 result->tm_mon = 0; 332 result->tm_year = 70; /* 1970 */ 333 334 if (_normalize_time(result, *timer) == -1) { 335 errno = EOVERFLOW; 89 int rc = utctime2tm(*timer, result); 90 if (rc != EOK) { 91 errno = rc; 336 92 return NULL; 337 93 } 338 94 339 95 return result; 96 } 97 98 /** 99 * Converts a time value to a broken-down UTC time. 100 * (non reentrant version) 101 * 102 * @param timep Time to convert 103 * @return Pointer to a statically allocated structure that stores 104 * the result, NULL in case of error. 105 */ 106 struct tm *posix_gmtime(const time_t *restrict timep) 107 { 108 static struct tm result; 109 110 return posix_gmtime_r(timep, &result); 340 111 } 341 112 … … 353 124 // currently assumes system and all times are in GMT 354 125 return posix_gmtime_r(timer, result); 126 } 127 128 /** 129 * Converts a time value to a broken-down local time. 130 * (non reentrant version) 131 * 132 * @param timep Time to convert. 133 * @return Pointer to a statically allocated structure that stores 134 * the result, NULL in case of error. 135 */ 136 struct tm *posix_localtime(const time_t *restrict timep) 137 { 138 static struct tm result; 139 140 return posix_localtime_r(timep, &result); 355 141 } 356 142 … … 367 153 char *restrict buf) 368 154 { 369 assert(timeptr != NULL); 370 assert(buf != NULL); 371 372 static const char *wday[] = { 373 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 374 }; 375 static const char *mon[] = { 376 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 377 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 378 }; 379 380 snprintf(buf, ASCTIME_BUF_LEN, "%s %s %2d %02d:%02d:%02d %d\n", 381 wday[timeptr->tm_wday], 382 mon[timeptr->tm_mon], 383 timeptr->tm_mday, timeptr->tm_hour, 384 timeptr->tm_min, timeptr->tm_sec, 385 1900 + timeptr->tm_year); 386 155 tm2str(timeptr, buf); 387 156 return buf; 388 157 } 389 158 390 159 /** 391 * Reentrant variant of ctime(). 160 * Convers broken-down time to a string in format 161 * "Sun Jan 1 00:00:00 1970\n". (Obsolete) 162 * (non reentrant version) 163 * 164 * @param timeptr Broken-down time structure. 165 * @return Pointer to a statically allocated buffer that stores 166 * the result, NULL in case of error. 167 */ 168 char *posix_asctime(const struct tm *restrict timeptr) 169 { 170 static char buf[ASCTIME_BUF_LEN]; 171 172 return posix_asctime_r(timeptr, buf); 173 } 174 175 /** 176 * Converts the calendar time to a string in format 177 * "Sun Jan 1 00:00:00 1970\n" (Obsolete) 392 178 * 393 179 * @param timer Time to convert. 394 180 * @param buf Buffer to store string to. Must be at least ASCTIME_BUF_LEN 395 181 * bytes long. 396 * @return Pointer to buf on success, NULL on fa lure.182 * @return Pointer to buf on success, NULL on failure. 397 183 */ 398 184 char *posix_ctime_r(const time_t *timer, char *buf) 399 185 { 400 struct tm loctime; 401 if (posix_localtime_r(timer, &loctime) == NULL) { 186 int r = localtime2str(*timer, buf); 187 if (r != EOK) { 188 errno = r; 402 189 return NULL; 403 190 } 404 return posix_asctime_r(&loctime, buf); 191 192 return buf; 193 } 194 195 /** 196 * Converts the calendar time to a string in format 197 * "Sun Jan 1 00:00:00 1970\n" (Obsolete) 198 * (non reentrant version) 199 * 200 * @param timep Time to convert. 201 * @return Pointer to a statically allocated buffer that stores 202 * the result, NULL in case of error. 203 */ 204 char *posix_ctime(const time_t *timep) 205 { 206 static char buf[ASCTIME_BUF_LEN]; 207 208 return posix_ctime_r(timep, buf); 405 209 } 406 210
Note:
See TracChangeset
for help on using the changeset viewer.