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