Changes in uspace/lib/posix/time.c [d3e3a71:d4d74dc] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/posix/time.c
rd3e3a71 rd4d74dc 45 45 #include "errno.h" 46 46 #include "signal.h" 47 #include "assert.h" 47 48 48 49 #include "libc/malloc.h" … … 140 141 * Used by some functions in this file. 141 142 * 142 * @param op1 Dividen d.143 * @param op1 Divident. 143 144 * @param op2 Divisor. 144 145 * @return Rounded quotient. … … 157 158 * Used by some functions in this file. 158 159 * 159 * @param op1 Dividen d.160 * @param op1 Divident. 160 161 * @param op2 Divisor. 161 162 * @return Remainder. … … 195 196 196 197 /** 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 /** 197 211 * Which day of week the specified date is. 198 212 * … … 216 230 * @return 0 on success, -1 on overflow 217 231 */ 218 static int _normalize_time(struct tm *tm, time_t sec_add)232 static int _normalize_time(struct posix_tm *tm, time_t sec_add) 219 233 { 220 234 // TODO: DST correction … … 292 306 } 293 307 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 previous 360 * year, and the next week is week 1. Both January 4th and the first Thursday 361 * 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 294 395 /******************************************************************************/ 295 396 … … 311 412 312 413 /** 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 time 427 * (moves all values to their proper bounds) and then tries to 428 * 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 account 436 // TODO: detect overflow 437 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 /** 313 457 * Converts a time value to a broken-down UTC time. 314 458 * … … 317 461 * @return Value of result on success, NULL on overflow. 318 462 */ 319 struct tm *posix_gmtime_r(const time_t *restrict timer,320 struct tm *restrict result)463 struct posix_tm *posix_gmtime_r(const time_t *restrict timer, 464 struct posix_tm *restrict result) 321 465 { 322 466 assert(timer != NULL); … … 341 485 /** 342 486 * 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. 343 499 * 344 500 * @param timer Time to convert. … … 346 502 * @return Value of result on success, NULL on overflow. 347 503 */ 348 struct tm *posix_localtime_r(const time_t *restrict timer,349 struct tm *restrict result)504 struct posix_tm *posix_localtime_r(const time_t *restrict timer, 505 struct posix_tm *restrict result) 350 506 { 351 507 // TODO: deal with timezone 352 508 // currently assumes system and all times are in GMT 353 509 return posix_gmtime_r(timer, result); 510 } 511 512 /** 513 * Converts broken-down time to a string in format 514 * "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); 354 523 } 355 524 … … 363 532 * @return Value of buf. 364 533 */ 365 char *posix_asctime_r(const struct tm *restrict timeptr,534 char *posix_asctime_r(const struct posix_tm *restrict timeptr, 366 535 char *restrict buf) 367 536 { … … 388 557 389 558 /** 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 /** 390 574 * Reentrant variant of ctime(). 391 575 * … … 397 581 char *posix_ctime_r(const time_t *timer, char *buf) 398 582 { 399 struct tm loctime;583 struct posix_tm loctime; 400 584 if (posix_localtime_r(timer, &loctime) == NULL) { 401 585 return NULL; 402 586 } 403 587 return posix_asctime_r(&loctime, buf); 588 } 589 590 /** 591 * Convert time and date to a string, based on a specified format and 592 * 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 locale 608 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: padding 665 format++; 666 } 667 while (isdigit(*format)) { 668 // TODO: padding 669 format++; 670 } 671 if (*format == 'O' || *format == 'E') { 672 // TODO: locale's alternative format 673 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 format 687 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 format 748 recurse("%Y-%m-%d"); break; 749 case 'X': 750 // TODO: locale-specific time format 751 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: timezone 758 break; 759 case 'Z': 760 // TODO: timezone 761 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 append 777 #undef recurse 778 779 return maxsize - remaining; 404 780 } 405 781 … … 518 894 stats_task_t *task_stats = stats_get_task(task_get_id()); 519 895 if (task_stats) { 520 total_cycles = (posix_clock_t) (task_stats->kcycles + 521 task_stats->ucycles); 896 total_cycles = (posix_clock_t) (task_stats->kcycles + task_stats->ucycles); 522 897 free(task_stats); 523 898 task_stats = 0;
Note:
See TracChangeset
for help on using the changeset viewer.