Changes in uspace/lib/posix/time.c [d4d74dc:d3e3a71] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/posix/time.c
rd4d74dc rd3e3a71 45 45 #include "errno.h" 46 46 #include "signal.h" 47 #include "assert.h"48 47 49 48 #include "libc/malloc.h" … … 141 140 * Used by some functions in this file. 142 141 * 143 * @param op1 Dividen t.142 * @param op1 Dividend. 144 143 * @param op2 Divisor. 145 144 * @return Rounded quotient. … … 158 157 * Used by some functions in this file. 159 158 * 160 * @param op1 Dividen t.159 * @param op1 Dividend. 161 160 * @param op2 Divisor. 162 161 * @return Remainder. … … 196 195 197 196 /** 198 * Seconds since the Epoch. see also _days_since_epoch().199 *200 * @param tm Normalized broken-down time.201 * @return Number of seconds since the epoch, not counting leap seconds.202 */203 static time_t _secs_since_epoch(const struct posix_tm *tm)204 {205 return _days_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday) *206 SECS_PER_DAY + tm->tm_hour * SECS_PER_HOUR +207 tm->tm_min * SECS_PER_MIN + tm->tm_sec;208 }209 210 /**211 197 * Which day of week the specified date is. 212 198 * … … 230 216 * @return 0 on success, -1 on overflow 231 217 */ 232 static int _normalize_time(struct posix_tm *tm, time_t sec_add)218 static int _normalize_time(struct tm *tm, time_t sec_add) 233 219 { 234 220 // TODO: DST correction … … 306 292 } 307 293 308 /**309 * Which day the week-based year starts on, relative to the first calendar day.310 * E.g. if the year starts on December 31st, the return value is -1.311 *312 * @param Year since 1900.313 * @return Offset of week-based year relative to calendar year.314 */315 static int _wbyear_offset(int year)316 {317 int start_wday = _day_of_week(year, 0, 1);318 return _floor_mod(4 - start_wday, 7) - 3;319 }320 321 /**322 * Returns week-based year of the specified time.323 *324 * @param tm Normalized broken-down time.325 * @return Week-based year.326 */327 static int _wbyear(const struct posix_tm *tm)328 {329 int day = tm->tm_yday - _wbyear_offset(tm->tm_year);330 if (day < 0) {331 /* Last week of previous year. */332 return tm->tm_year - 1;333 }334 if (day > 364 + _is_leap_year(tm->tm_year)) {335 /* First week of next year. */336 return tm->tm_year + 1;337 }338 /* All the other days are in the calendar year. */339 return tm->tm_year;340 }341 342 /**343 * Week number of the year, assuming weeks start on sunday.344 * The first Sunday of January is the first day of week 1;345 * days in the new year before this are in week 0.346 *347 * @param tm Normalized broken-down time.348 * @return The week number (0 - 53).349 */350 static int _sun_week_number(const struct posix_tm *tm)351 {352 int first_day = (7 - _day_of_week(tm->tm_year, 0, 1)) % 7;353 return (tm->tm_yday - first_day + 7) / 7;354 }355 356 /**357 * Week number of the year, assuming weeks start on monday.358 * If the week containing January 1st has four or more days in the new year,359 * then it is considered week 1. Otherwise, it is the last week of the previous360 * year, and the next week is week 1. Both January 4th and the first Thursday361 * of January are always in week 1.362 *363 * @param tm Normalized broken-down time.364 * @return The week number (1 - 53).365 */366 static int _iso_week_number(const struct posix_tm *tm)367 {368 int day = tm->tm_yday - _wbyear_offset(tm->tm_year);369 if (day < 0) {370 /* Last week of previous year. */371 return 53;372 }373 if (day > 364 + _is_leap_year(tm->tm_year)) {374 /* First week of next year. */375 return 1;376 }377 /* All the other days give correct answer. */378 return (day / 7 + 1);379 }380 381 /**382 * Week number of the year, assuming weeks start on monday.383 * The first Monday of January is the first day of week 1;384 * days in the new year before this are in week 0.385 *386 * @param tm Normalized broken-down time.387 * @return The week number (0 - 53).388 */389 static int _mon_week_number(const struct posix_tm *tm)390 {391 int first_day = (1 - _day_of_week(tm->tm_year, 0, 1)) % 7;392 return (tm->tm_yday - first_day + 7) / 7;393 }394 395 294 /******************************************************************************/ 396 295 … … 412 311 413 312 /** 414 * Calculate the difference between two times, in seconds.415 *416 * @param time1 First time.417 * @param time0 Second time.418 * @return Time in seconds.419 */420 double posix_difftime(time_t time1, time_t time0)421 {422 return (double) (time1 - time0);423 }424 425 /**426 * This function first normalizes the provided broken-down time427 * (moves all values to their proper bounds) and then tries to428 * calculate the appropriate time_t representation.429 *430 * @param tm Broken-down time.431 * @return time_t representation of the time, undefined value on overflow.432 */433 time_t posix_mktime(struct posix_tm *tm)434 {435 // TODO: take DST flag into account436 // TODO: detect overflow437 438 _normalize_time(tm, 0);439 return _secs_since_epoch(tm);440 }441 442 /**443 * Converts a time value to a broken-down UTC time.444 *445 * @param timer Time to convert.446 * @return Normalized broken-down time in UTC, NULL on overflow.447 */448 struct posix_tm *posix_gmtime(const time_t *timer)449 {450 assert(timer != NULL);451 452 static struct posix_tm result;453 return posix_gmtime_r(timer, &result);454 }455 456 /**457 313 * Converts a time value to a broken-down UTC time. 458 314 * … … 461 317 * @return Value of result on success, NULL on overflow. 462 318 */ 463 struct posix_tm *posix_gmtime_r(const time_t *restrict timer,464 struct posix_tm *restrict result)319 struct tm *posix_gmtime_r(const time_t *restrict timer, 320 struct tm *restrict result) 465 321 { 466 322 assert(timer != NULL); … … 485 341 /** 486 342 * Converts a time value to a broken-down local time. 487 *488 * @param timer Time to convert.489 * @return Normalized broken-down time in local timezone, NULL on overflow.490 */491 struct posix_tm *posix_localtime(const time_t *timer)492 {493 static struct posix_tm result;494 return posix_localtime_r(timer, &result);495 }496 497 /**498 * Converts a time value to a broken-down local time.499 343 * 500 344 * @param timer Time to convert. … … 502 346 * @return Value of result on success, NULL on overflow. 503 347 */ 504 struct posix_tm *posix_localtime_r(const time_t *restrict timer,505 struct posix_tm *restrict result)348 struct tm *posix_localtime_r(const time_t *restrict timer, 349 struct tm *restrict result) 506 350 { 507 351 // TODO: deal with timezone 508 352 // currently assumes system and all times are in GMT 509 353 return posix_gmtime_r(timer, result); 510 }511 512 /**513 * Converts broken-down time to a string in format514 * "Sun Jan 1 00:00:00 1970\n". (Obsolete)515 *516 * @param timeptr Broken-down time structure.517 * @return Pointer to a statically allocated string.518 */519 char *posix_asctime(const struct posix_tm *timeptr)520 {521 static char buf[ASCTIME_BUF_LEN];522 return posix_asctime_r(timeptr, buf);523 354 } 524 355 … … 532 363 * @return Value of buf. 533 364 */ 534 char *posix_asctime_r(const struct posix_tm *restrict timeptr,365 char *posix_asctime_r(const struct tm *restrict timeptr, 535 366 char *restrict buf) 536 367 { … … 557 388 558 389 /** 559 * Equivalent to asctime(localtime(clock)).560 *561 * @param timer Time to convert.562 * @return Pointer to a statically allocated string holding the date.563 */564 char *posix_ctime(const time_t *timer)565 {566 struct posix_tm *loctime = posix_localtime(timer);567 if (loctime == NULL) {568 return NULL;569 }570 return posix_asctime(loctime);571 }572 573 /**574 390 * Reentrant variant of ctime(). 575 391 * … … 581 397 char *posix_ctime_r(const time_t *timer, char *buf) 582 398 { 583 struct posix_tm loctime;399 struct tm loctime; 584 400 if (posix_localtime_r(timer, &loctime) == NULL) { 585 401 return NULL; 586 402 } 587 403 return posix_asctime_r(&loctime, buf); 588 }589 590 /**591 * Convert time and date to a string, based on a specified format and592 * current locale.593 *594 * @param s Buffer to write string to.595 * @param maxsize Size of the buffer.596 * @param format Format of the output.597 * @param tm Broken-down time to format.598 * @return Number of bytes written.599 */600 size_t posix_strftime(char *restrict s, size_t maxsize,601 const char *restrict format, const struct posix_tm *restrict tm)602 {603 assert(s != NULL);604 assert(format != NULL);605 assert(tm != NULL);606 607 // TODO: use locale608 static const char *wday_abbr[] = {609 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"610 };611 static const char *wday[] = {612 "Sunday", "Monday", "Tuesday", "Wednesday",613 "Thursday", "Friday", "Saturday"614 };615 static const char *mon_abbr[] = {616 "Jan", "Feb", "Mar", "Apr", "May", "Jun",617 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"618 };619 static const char *mon[] = {620 "January", "February", "March", "April", "May", "June", "July",621 "August", "September", "October", "November", "December"622 };623 624 if (maxsize < 1) {625 return 0;626 }627 628 char *ptr = s;629 size_t consumed;630 size_t remaining = maxsize;631 632 #define append(...) { \633 /* FIXME: this requires POSIX-correct snprintf */ \634 /* otherwise it won't work with non-ascii chars */ \635 consumed = snprintf(ptr, remaining, __VA_ARGS__); \636 if (consumed >= remaining) { \637 return 0; \638 } \639 ptr += consumed; \640 remaining -= consumed; \641 }642 643 #define recurse(fmt) { \644 consumed = posix_strftime(ptr, remaining, fmt, tm); \645 if (consumed == 0) { \646 return 0; \647 } \648 ptr += consumed; \649 remaining -= consumed; \650 }651 652 #define TO_12H(hour) (((hour) > 12) ? ((hour) - 12) : \653 (((hour) == 0) ? 12 : (hour)))654 655 while (*format != '\0') {656 if (*format != '%') {657 append("%c", *format);658 format++;659 continue;660 }661 662 format++;663 if (*format == '0' || *format == '+') {664 // TODO: padding665 format++;666 }667 while (isdigit(*format)) {668 // TODO: padding669 format++;670 }671 if (*format == 'O' || *format == 'E') {672 // TODO: locale's alternative format673 format++;674 }675 676 switch (*format) {677 case 'a':678 append("%s", wday_abbr[tm->tm_wday]); break;679 case 'A':680 append("%s", wday[tm->tm_wday]); break;681 case 'b':682 append("%s", mon_abbr[tm->tm_mon]); break;683 case 'B':684 append("%s", mon[tm->tm_mon]); break;685 case 'c':686 // TODO: locale-specific datetime format687 recurse("%Y-%m-%d %H:%M:%S"); break;688 case 'C':689 append("%02d", (1900 + tm->tm_year) / 100); break;690 case 'd':691 append("%02d", tm->tm_mday); break;692 case 'D':693 recurse("%m/%d/%y"); break;694 case 'e':695 append("%2d", tm->tm_mday); break;696 case 'F':697 recurse("%+4Y-%m-%d"); break;698 case 'g':699 append("%02d", _wbyear(tm) % 100); break;700 case 'G':701 append("%d", _wbyear(tm)); break;702 case 'h':703 recurse("%b"); break;704 case 'H':705 append("%02d", tm->tm_hour); break;706 case 'I':707 append("%02d", TO_12H(tm->tm_hour)); break;708 case 'j':709 append("%03d", tm->tm_yday); break;710 case 'k':711 append("%2d", tm->tm_hour); break;712 case 'l':713 append("%2d", TO_12H(tm->tm_hour)); break;714 case 'm':715 append("%02d", tm->tm_mon); break;716 case 'M':717 append("%02d", tm->tm_min); break;718 case 'n':719 append("\n"); break;720 case 'p':721 append("%s", tm->tm_hour < 12 ? "AM" : "PM"); break;722 case 'P':723 append("%s", tm->tm_hour < 12 ? "am" : "PM"); break;724 case 'r':725 recurse("%I:%M:%S %p"); break;726 case 'R':727 recurse("%H:%M"); break;728 case 's':729 append("%ld", _secs_since_epoch(tm)); break;730 case 'S':731 append("%02d", tm->tm_sec); break;732 case 't':733 append("\t"); break;734 case 'T':735 recurse("%H:%M:%S"); break;736 case 'u':737 append("%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday); break;738 case 'U':739 append("%02d", _sun_week_number(tm)); break;740 case 'V':741 append("%02d", _iso_week_number(tm)); break;742 case 'w':743 append("%d", tm->tm_wday); break;744 case 'W':745 append("%02d", _mon_week_number(tm)); break;746 case 'x':747 // TODO: locale-specific date format748 recurse("%Y-%m-%d"); break;749 case 'X':750 // TODO: locale-specific time format751 recurse("%H:%M:%S"); break;752 case 'y':753 append("%02d", tm->tm_year % 100); break;754 case 'Y':755 append("%d", 1900 + tm->tm_year); break;756 case 'z':757 // TODO: timezone758 break;759 case 'Z':760 // TODO: timezone761 break;762 case '%':763 append("%%");764 break;765 default:766 /* Invalid specifier, print verbatim. */767 while (*format != '%') {768 format--;769 }770 append("%%");771 break;772 }773 format++;774 }775 776 #undef append777 #undef recurse778 779 return maxsize - remaining;780 404 } 781 405 … … 894 518 stats_task_t *task_stats = stats_get_task(task_get_id()); 895 519 if (task_stats) { 896 total_cycles = (posix_clock_t) (task_stats->kcycles + task_stats->ucycles); 520 total_cycles = (posix_clock_t) (task_stats->kcycles + 521 task_stats->ucycles); 897 522 free(task_stats); 898 523 task_stats = 0;
Note:
See TracChangeset
for help on using the changeset viewer.