Changeset 3293a94 in mainline
- Timestamp:
- 2012-04-23T22:40:02Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 7719958
- Parents:
- 4cade47 (diff), d3e3a71 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Location:
- uspace/lib
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/time.c
r4cade47 r3293a94 1 1 /* 2 2 * Copyright (c) 2006 Ondrej Palkovsky 3 * Copyright (c) 2011 Petr Koupy 4 * Copyright (c) 2011 Jiri Zarevucky 3 5 * All rights reserved. 4 6 * … … 43 45 #include <ddi.h> 44 46 #include <libc.h> 47 #include <stdint.h> 48 #include <stdio.h> 49 #include <ctype.h> 50 51 #define ASCTIME_BUF_LEN 26 45 52 46 53 /** Pointer to kernel shared variables with time */ … … 50 57 volatile sysarg_t seconds2; 51 58 } *ktime = NULL; 59 60 /* Helper functions ***********************************************************/ 61 62 #define HOURS_PER_DAY (24) 63 #define MINS_PER_HOUR (60) 64 #define SECS_PER_MIN (60) 65 #define MINS_PER_DAY (MINS_PER_HOUR * HOURS_PER_DAY) 66 #define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR) 67 #define SECS_PER_DAY (SECS_PER_HOUR * HOURS_PER_DAY) 68 69 /** 70 * Checks whether the year is a leap year. 71 * 72 * @param year Year since 1900 (e.g. for 1970, the value is 70). 73 * @return true if year is a leap year, false otherwise 74 */ 75 static bool _is_leap_year(time_t year) 76 { 77 year += 1900; 78 79 if (year % 400 == 0) 80 return true; 81 if (year % 100 == 0) 82 return false; 83 if (year % 4 == 0) 84 return true; 85 return false; 86 } 87 88 /** 89 * Returns how many days there are in the given month of the given year. 90 * Note that year is only taken into account if month is February. 91 * 92 * @param year Year since 1900 (can be negative). 93 * @param mon Month of the year. 0 for January, 11 for December. 94 * @return Number of days in the specified month. 95 */ 96 static int _days_in_month(time_t year, time_t mon) 97 { 98 assert(mon >= 0 && mon <= 11); 99 100 static int month_days[] = 101 { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 102 103 if (mon == 1) { 104 year += 1900; 105 /* february */ 106 return _is_leap_year(year) ? 29 : 28; 107 } else { 108 return month_days[mon]; 109 } 110 } 111 112 /** 113 * For specified year, month and day of month, returns which day of that year 114 * it is. 115 * 116 * For example, given date 2011-01-03, the corresponding expression is: 117 * _day_of_year(111, 0, 3) == 2 118 * 119 * @param year Year (year 1900 = 0, can be negative). 120 * @param mon Month (January = 0). 121 * @param mday Day of month (First day is 1). 122 * @return Day of year (First day is 0). 123 */ 124 static int _day_of_year(time_t year, time_t mon, time_t mday) 125 { 126 static int mdays[] = 127 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; 128 static int leap_mdays[] = 129 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }; 130 131 return (_is_leap_year(year) ? leap_mdays[mon] : mdays[mon]) + mday - 1; 132 } 133 134 /** 135 * Integer division that rounds to negative infinity. 136 * Used by some functions in this file. 137 * 138 * @param op1 Dividend. 139 * @param op2 Divisor. 140 * @return Rounded quotient. 141 */ 142 static time_t _floor_div(time_t op1, time_t op2) 143 { 144 if (op1 >= 0 || op1 % op2 == 0) { 145 return op1 / op2; 146 } else { 147 return op1 / op2 - 1; 148 } 149 } 150 151 /** 152 * Modulo that rounds to negative infinity. 153 * Used by some functions in this file. 154 * 155 * @param op1 Dividend. 156 * @param op2 Divisor. 157 * @return Remainder. 158 */ 159 static time_t _floor_mod(time_t op1, time_t op2) 160 { 161 int div = _floor_div(op1, op2); 162 163 /* (a / b) * b + a % b == a */ 164 /* thus, a % b == a - (a / b) * b */ 165 166 int result = op1 - div * op2; 167 168 /* Some paranoid checking to ensure I didn't make a mistake here. */ 169 assert(result >= 0); 170 assert(result < op2); 171 assert(div * op2 + result == op1); 172 173 return result; 174 } 175 176 /** 177 * Number of days since the Epoch. 178 * Epoch is 1970-01-01, which is also equal to day 0. 179 * 180 * @param year Year (year 1900 = 0, may be negative). 181 * @param mon Month (January = 0). 182 * @param mday Day of month (first day = 1). 183 * @return Number of days since the Epoch. 184 */ 185 static time_t _days_since_epoch(time_t year, time_t mon, time_t mday) 186 { 187 return (year - 70) * 365 + _floor_div(year - 69, 4) - 188 _floor_div(year - 1, 100) + _floor_div(year + 299, 400) + 189 _day_of_year(year, mon, mday); 190 } 191 192 /** 193 * Seconds since the Epoch. see also _days_since_epoch(). 194 * 195 * @param tm Normalized broken-down time. 196 * @return Number of seconds since the epoch, not counting leap seconds. 197 */ 198 static time_t _secs_since_epoch(const struct tm *tm) 199 { 200 return _days_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday) * 201 SECS_PER_DAY + tm->tm_hour * SECS_PER_HOUR + 202 tm->tm_min * SECS_PER_MIN + tm->tm_sec; 203 } 204 205 /** 206 * Which day of week the specified date is. 207 * 208 * @param year Year (year 1900 = 0). 209 * @param mon Month (January = 0). 210 * @param mday Day of month (first = 1). 211 * @return Day of week (Sunday = 0). 212 */ 213 static int _day_of_week(time_t year, time_t mon, time_t mday) 214 { 215 /* 1970-01-01 is Thursday */ 216 return _floor_mod((_days_since_epoch(year, mon, mday) + 4), 7); 217 } 218 219 /** 220 * Normalizes the broken-down time and optionally adds specified amount of 221 * seconds. 222 * 223 * @param tm Broken-down time to normalize. 224 * @param sec_add Seconds to add. 225 * @return 0 on success, -1 on overflow 226 */ 227 static int _normalize_time(struct tm *tm, time_t sec_add) 228 { 229 // TODO: DST correction 230 231 /* Set initial values. */ 232 time_t sec = tm->tm_sec + sec_add; 233 time_t min = tm->tm_min; 234 time_t hour = tm->tm_hour; 235 time_t day = tm->tm_mday - 1; 236 time_t mon = tm->tm_mon; 237 time_t year = tm->tm_year; 238 239 /* Adjust time. */ 240 min += _floor_div(sec, SECS_PER_MIN); 241 sec = _floor_mod(sec, SECS_PER_MIN); 242 hour += _floor_div(min, MINS_PER_HOUR); 243 min = _floor_mod(min, MINS_PER_HOUR); 244 day += _floor_div(hour, HOURS_PER_DAY); 245 hour = _floor_mod(hour, HOURS_PER_DAY); 246 247 /* Adjust month. */ 248 year += _floor_div(mon, 12); 249 mon = _floor_mod(mon, 12); 250 251 /* Now the difficult part - days of month. */ 252 253 /* First, deal with whole cycles of 400 years = 146097 days. */ 254 year += _floor_div(day, 146097) * 400; 255 day = _floor_mod(day, 146097); 256 257 /* Then, go in one year steps. */ 258 if (mon <= 1) { 259 /* January and February. */ 260 while (day > 365) { 261 day -= _is_leap_year(year) ? 366 : 365; 262 year++; 263 } 264 } else { 265 /* Rest of the year. */ 266 while (day > 365) { 267 day -= _is_leap_year(year + 1) ? 366 : 365; 268 year++; 269 } 270 } 271 272 /* Finally, finish it off month per month. */ 273 while (day >= _days_in_month(year, mon)) { 274 day -= _days_in_month(year, mon); 275 mon++; 276 if (mon >= 12) { 277 mon -= 12; 278 year++; 279 } 280 } 281 282 /* Calculate the remaining two fields. */ 283 tm->tm_yday = _day_of_year(year, mon, day + 1); 284 tm->tm_wday = _day_of_week(year, mon, day + 1); 285 286 /* And put the values back to the struct. */ 287 tm->tm_sec = (int) sec; 288 tm->tm_min = (int) min; 289 tm->tm_hour = (int) hour; 290 tm->tm_mday = (int) day + 1; 291 tm->tm_mon = (int) mon; 292 293 /* Casts to work around libc brain-damage. */ 294 if (year > ((int)INT_MAX) || year < ((int)INT_MIN)) { 295 tm->tm_year = (year < 0) ? ((int)INT_MIN) : ((int)INT_MAX); 296 return -1; 297 } 298 299 tm->tm_year = (int) year; 300 return 0; 301 } 302 303 /** 304 * Which day the week-based year starts on, relative to the first calendar day. 305 * E.g. if the year starts on December 31st, the return value is -1. 306 * 307 * @param Year since 1900. 308 * @return Offset of week-based year relative to calendar year. 309 */ 310 static int _wbyear_offset(int year) 311 { 312 int start_wday = _day_of_week(year, 0, 1); 313 return _floor_mod(4 - start_wday, 7) - 3; 314 } 315 316 /** 317 * Returns week-based year of the specified time. 318 * 319 * @param tm Normalized broken-down time. 320 * @return Week-based year. 321 */ 322 static int _wbyear(const struct tm *tm) 323 { 324 int day = tm->tm_yday - _wbyear_offset(tm->tm_year); 325 if (day < 0) { 326 /* Last week of previous year. */ 327 return tm->tm_year - 1; 328 } 329 if (day > 364 + _is_leap_year(tm->tm_year)) { 330 /* First week of next year. */ 331 return tm->tm_year + 1; 332 } 333 /* All the other days are in the calendar year. */ 334 return tm->tm_year; 335 } 336 337 /** 338 * Week number of the year, assuming weeks start on sunday. 339 * The first Sunday of January is the first day of week 1; 340 * days in the new year before this are in week 0. 341 * 342 * @param tm Normalized broken-down time. 343 * @return The week number (0 - 53). 344 */ 345 static int _sun_week_number(const struct tm *tm) 346 { 347 int first_day = (7 - _day_of_week(tm->tm_year, 0, 1)) % 7; 348 return (tm->tm_yday - first_day + 7) / 7; 349 } 350 351 /** 352 * Week number of the year, assuming weeks start on monday. 353 * If the week containing January 1st has four or more days in the new year, 354 * then it is considered week 1. Otherwise, it is the last week of the previous 355 * year, and the next week is week 1. Both January 4th and the first Thursday 356 * of January are always in week 1. 357 * 358 * @param tm Normalized broken-down time. 359 * @return The week number (1 - 53). 360 */ 361 static int _iso_week_number(const struct tm *tm) 362 { 363 int day = tm->tm_yday - _wbyear_offset(tm->tm_year); 364 if (day < 0) { 365 /* Last week of previous year. */ 366 return 53; 367 } 368 if (day > 364 + _is_leap_year(tm->tm_year)) { 369 /* First week of next year. */ 370 return 1; 371 } 372 /* All the other days give correct answer. */ 373 return (day / 7 + 1); 374 } 375 376 /** 377 * Week number of the year, assuming weeks start on monday. 378 * The first Monday of January is the first day of week 1; 379 * days in the new year before this are in week 0. 380 * 381 * @param tm Normalized broken-down time. 382 * @return The week number (0 - 53). 383 */ 384 static int _mon_week_number(const struct tm *tm) 385 { 386 int first_day = (1 - _day_of_week(tm->tm_year, 0, 1)) % 7; 387 return (tm->tm_yday - first_day + 7) / 7; 388 } 389 390 /******************************************************************************/ 391 52 392 53 393 /** Add microseconds to given timeval. … … 228 568 } 229 569 570 /** 571 * This function first normalizes the provided broken-down time 572 * (moves all values to their proper bounds) and then tries to 573 * calculate the appropriate time_t representation. 574 * 575 * @param tm Broken-down time. 576 * @return time_t representation of the time, undefined value on overflow. 577 */ 578 time_t mktime(struct tm *tm) 579 { 580 // TODO: take DST flag into account 581 // TODO: detect overflow 582 583 _normalize_time(tm, 0); 584 return _secs_since_epoch(tm); 585 } 586 587 /** 588 * Convert time and date to a string, based on a specified format and 589 * current locale. 590 * 591 * @param s Buffer to write string to. 592 * @param maxsize Size of the buffer. 593 * @param format Format of the output. 594 * @param tm Broken-down time to format. 595 * @return Number of bytes written. 596 */ 597 size_t strftime(char *restrict s, size_t maxsize, 598 const char *restrict format, const struct tm *restrict tm) 599 { 600 assert(s != NULL); 601 assert(format != NULL); 602 assert(tm != NULL); 603 604 // TODO: use locale 605 static const char *wday_abbr[] = { 606 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 607 }; 608 static const char *wday[] = { 609 "Sunday", "Monday", "Tuesday", "Wednesday", 610 "Thursday", "Friday", "Saturday" 611 }; 612 static const char *mon_abbr[] = { 613 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 614 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 615 }; 616 static const char *mon[] = { 617 "January", "February", "March", "April", "May", "June", "July", 618 "August", "September", "October", "November", "December" 619 }; 620 621 if (maxsize < 1) { 622 return 0; 623 } 624 625 char *ptr = s; 626 size_t consumed; 627 size_t remaining = maxsize; 628 629 #define append(...) { \ 630 /* FIXME: this requires POSIX-correct snprintf */ \ 631 /* otherwise it won't work with non-ascii chars */ \ 632 consumed = snprintf(ptr, remaining, __VA_ARGS__); \ 633 if (consumed >= remaining) { \ 634 return 0; \ 635 } \ 636 ptr += consumed; \ 637 remaining -= consumed; \ 638 } 639 640 #define recurse(fmt) { \ 641 consumed = strftime(ptr, remaining, fmt, tm); \ 642 if (consumed == 0) { \ 643 return 0; \ 644 } \ 645 ptr += consumed; \ 646 remaining -= consumed; \ 647 } 648 649 #define TO_12H(hour) (((hour) > 12) ? ((hour) - 12) : \ 650 (((hour) == 0) ? 12 : (hour))) 651 652 while (*format != '\0') { 653 if (*format != '%') { 654 append("%c", *format); 655 format++; 656 continue; 657 } 658 659 format++; 660 if (*format == '0' || *format == '+') { 661 // TODO: padding 662 format++; 663 } 664 while (isdigit(*format)) { 665 // TODO: padding 666 format++; 667 } 668 if (*format == 'O' || *format == 'E') { 669 // TODO: locale's alternative format 670 format++; 671 } 672 673 switch (*format) { 674 case 'a': 675 append("%s", wday_abbr[tm->tm_wday]); break; 676 case 'A': 677 append("%s", wday[tm->tm_wday]); break; 678 case 'b': 679 append("%s", mon_abbr[tm->tm_mon]); break; 680 case 'B': 681 append("%s", mon[tm->tm_mon]); break; 682 case 'c': 683 // TODO: locale-specific datetime format 684 recurse("%Y-%m-%d %H:%M:%S"); break; 685 case 'C': 686 append("%02d", (1900 + tm->tm_year) / 100); break; 687 case 'd': 688 append("%02d", tm->tm_mday); break; 689 case 'D': 690 recurse("%m/%d/%y"); break; 691 case 'e': 692 append("%2d", tm->tm_mday); break; 693 case 'F': 694 recurse("%+4Y-%m-%d"); break; 695 case 'g': 696 append("%02d", _wbyear(tm) % 100); break; 697 case 'G': 698 append("%d", _wbyear(tm)); break; 699 case 'h': 700 recurse("%b"); break; 701 case 'H': 702 append("%02d", tm->tm_hour); break; 703 case 'I': 704 append("%02d", TO_12H(tm->tm_hour)); break; 705 case 'j': 706 append("%03d", tm->tm_yday); break; 707 case 'k': 708 append("%2d", tm->tm_hour); break; 709 case 'l': 710 append("%2d", TO_12H(tm->tm_hour)); break; 711 case 'm': 712 append("%02d", tm->tm_mon); break; 713 case 'M': 714 append("%02d", tm->tm_min); break; 715 case 'n': 716 append("\n"); break; 717 case 'p': 718 append("%s", tm->tm_hour < 12 ? "AM" : "PM"); break; 719 case 'P': 720 append("%s", tm->tm_hour < 12 ? "am" : "PM"); break; 721 case 'r': 722 recurse("%I:%M:%S %p"); break; 723 case 'R': 724 recurse("%H:%M"); break; 725 case 's': 726 append("%ld", _secs_since_epoch(tm)); break; 727 case 'S': 728 append("%02d", tm->tm_sec); break; 729 case 't': 730 append("\t"); break; 731 case 'T': 732 recurse("%H:%M:%S"); break; 733 case 'u': 734 append("%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday); 735 break; 736 case 'U': 737 append("%02d", _sun_week_number(tm)); break; 738 case 'V': 739 append("%02d", _iso_week_number(tm)); break; 740 case 'w': 741 append("%d", tm->tm_wday); break; 742 case 'W': 743 append("%02d", _mon_week_number(tm)); break; 744 case 'x': 745 // TODO: locale-specific date format 746 recurse("%Y-%m-%d"); break; 747 case 'X': 748 // TODO: locale-specific time format 749 recurse("%H:%M:%S"); break; 750 case 'y': 751 append("%02d", tm->tm_year % 100); break; 752 case 'Y': 753 append("%d", 1900 + tm->tm_year); break; 754 case 'z': 755 // TODO: timezone 756 break; 757 case 'Z': 758 // TODO: timezone 759 break; 760 case '%': 761 append("%%"); 762 break; 763 default: 764 /* Invalid specifier, print verbatim. */ 765 while (*format != '%') { 766 format--; 767 } 768 append("%%"); 769 break; 770 } 771 format++; 772 } 773 774 #undef append 775 #undef recurse 776 777 return maxsize - remaining; 778 } 779 780 struct tm *gmtime(const time_t *timer) 781 { 782 assert(timer != NULL); 783 784 static struct tm result; 785 786 /* Set result to epoch. */ 787 result.tm_sec = 0; 788 result.tm_min = 0; 789 result.tm_hour = 0; 790 result.tm_mday = 1; 791 result.tm_mon = 0; 792 result.tm_year = 70; /* 1970 */ 793 794 if (_normalize_time(&result, *timer) == -1) { 795 errno = EOVERFLOW; 796 return NULL; 797 } 798 799 return &result; 800 } 801 802 /** 803 * Converts broken-down time to a string in format 804 * "Sun Jan 1 00:00:00 1970\n". (Obsolete) 805 * 806 * @param timeptr Broken-down time structure. 807 * @return Pointer to a statically allocated string. 808 */ 809 char *asctime(const struct tm *timeptr) 810 { 811 static char buf[ASCTIME_BUF_LEN]; 812 813 assert(timeptr != NULL); 814 815 static const char *wday[] = { 816 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 817 }; 818 static const char *mon[] = { 819 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 820 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 821 }; 822 823 snprintf(buf, ASCTIME_BUF_LEN, "%s %s %2d %02d:%02d:%02d %d\n", 824 wday[timeptr->tm_wday], 825 mon[timeptr->tm_mon], 826 timeptr->tm_mday, timeptr->tm_hour, 827 timeptr->tm_min, timeptr->tm_sec, 828 1900 + timeptr->tm_year); 829 830 return buf; 831 832 } 833 834 /** 835 * Converts a time value to a broken-down local time. 836 * 837 * @param timer Time to convert. 838 * @return Normalized broken-down time in local timezone, NULL on overflow. 839 */ 840 struct tm *localtime(const time_t *timer) 841 { 842 // TODO: deal with timezone 843 // currently assumes system and all times are in GMT 844 845 static struct tm result; 846 847 /* Set result to epoch. */ 848 result.tm_sec = 0; 849 result.tm_min = 0; 850 result.tm_hour = 0; 851 result.tm_mday = 1; 852 result.tm_mon = 0; 853 result.tm_year = 70; /* 1970 */ 854 855 if (_normalize_time(&result, *timer) == -1) { 856 errno = EOVERFLOW; 857 return NULL; 858 } 859 860 return &result; 861 } 862 863 /** 864 * Equivalent to asctime(localtime(clock)). 865 * 866 * @param timer Time to convert. 867 * @return Pointer to a statically allocated string holding the date. 868 */ 869 char *ctime(const time_t *timer) 870 { 871 struct tm *loctime = localtime(timer); 872 if (loctime == NULL) { 873 return NULL; 874 } 875 return asctime(loctime); 876 } 877 878 /** 879 * Calculate the difference between two times, in seconds. 880 * 881 * @param time1 First time. 882 * @param time0 Second time. 883 * @return Time in seconds. 884 */ 885 double difftime(time_t time1, time_t time0) 886 { 887 return (double) (time1 - time0); 888 } 889 230 890 /** @} 231 891 */ -
uspace/lib/c/include/sys/time.h
r4cade47 r3293a94 41 41 42 42 #define DST_NONE 0 43 #define ASCTIME_BUF_LEN 26 43 44 44 45 typedef long time_t; … … 78 79 extern void udelay(useconds_t); 79 80 81 extern time_t mktime(struct tm *tm); 82 extern struct tm *gmtime(const time_t *timer); 83 extern char *asctime(const struct tm *timeptr); 84 extern struct tm *localtime(const time_t *timer); 85 extern char *ctime(const time_t *timer); 86 extern double difftime(time_t time1, time_t time0); 87 extern size_t strftime(char *restrict s, size_t maxsize, 88 const char *restrict format, const struct tm *restrict tm); 89 80 90 #endif 81 91 -
uspace/lib/posix/time.c
r4cade47 r3293a94 192 192 _floor_div(year - 1, 100) + _floor_div(year + 299, 400) + 193 193 _day_of_year(year, mon, mday); 194 }195 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 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 194 } 208 195 … … 305 292 } 306 293 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 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 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 previous359 * year, and the next week is week 1. Both January 4th and the first Thursday360 * 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 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 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 394 294 /******************************************************************************/ 395 295 … … 408 308 posix_daylight = 0; 409 309 posix_timezone = 0; 410 }411 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 time426 * (moves all values to their proper bounds) and then tries to427 * 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 tm *tm)433 {434 // TODO: take DST flag into account435 // TODO: detect overflow436 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 tm *posix_gmtime(const time_t *timer)448 {449 assert(timer != NULL);450 451 static struct tm result;452 return posix_gmtime_r(timer, &result);453 310 } 454 311 … … 484 341 /** 485 342 * 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 tm *posix_localtime(const time_t *timer)491 {492 static struct tm result;493 return posix_localtime_r(timer, &result);494 }495 496 /**497 * Converts a time value to a broken-down local time.498 343 * 499 344 * @param timer Time to convert. … … 507 352 // currently assumes system and all times are in GMT 508 353 return posix_gmtime_r(timer, result); 509 }510 511 /**512 * Converts broken-down time to a string in format513 * "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 tm *timeptr)519 {520 static char buf[ASCTIME_BUF_LEN];521 return posix_asctime_r(timeptr, buf);522 354 } 523 355 … … 556 388 557 389 /** 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 tm *loctime = posix_localtime(timer);566 if (loctime == NULL) {567 return NULL;568 }569 return posix_asctime(loctime);570 }571 572 /**573 390 * Reentrant variant of ctime(). 574 391 * … … 585 402 } 586 403 return posix_asctime_r(&loctime, buf); 587 }588 589 /**590 * Convert time and date to a string, based on a specified format and591 * 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 tm *restrict tm)601 {602 assert(s != NULL);603 assert(format != NULL);604 assert(tm != NULL);605 606 // TODO: use locale607 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: padding664 format++;665 }666 while (isdigit(*format)) {667 // TODO: padding668 format++;669 }670 if (*format == 'O' || *format == 'E') {671 // TODO: locale's alternative format672 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 format686 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 format747 recurse("%Y-%m-%d"); break;748 case 'X':749 // TODO: locale-specific time format750 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: timezone757 break;758 case 'Z':759 // TODO: timezone760 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 append776 #undef recurse777 778 return maxsize - remaining;779 404 } 780 405 … … 893 518 stats_task_t *task_stats = stats_get_task(task_get_id()); 894 519 if (task_stats) { 895 total_cycles = (posix_clock_t) (task_stats->kcycles + task_stats->ucycles); 520 total_cycles = (posix_clock_t) (task_stats->kcycles + 521 task_stats->ucycles); 896 522 free(task_stats); 897 523 task_stats = 0; -
uspace/lib/posix/time.h
r4cade47 r3293a94 63 63 #endif 64 64 65 #undef ASCTIME_BUF_LEN66 #define ASCTIME_BUF_LEN 2667 68 65 #undef CLOCK_REALTIME 69 66 #define CLOCK_REALTIME ((posix_clockid_t) 0) … … 87 84 extern void posix_tzset(void); 88 85 89 /* Elapsed Time */90 extern double posix_difftime(time_t time1, time_t time0);91 92 86 /* Broken-down Time */ 93 extern time_t posix_mktime(struct tm *tm);94 extern struct tm *posix_gmtime(const time_t *timer);95 87 extern struct tm *posix_gmtime_r(const time_t *restrict timer, 96 88 struct tm *restrict result); 97 extern struct tm *posix_localtime(const time_t *timer);98 89 extern struct tm *posix_localtime_r(const time_t *restrict timer, 99 90 struct tm *restrict result); 100 91 101 92 /* Formatting Calendar Time */ 102 extern char *posix_asctime(const struct tm *timeptr);103 93 extern char *posix_asctime_r(const struct tm *restrict timeptr, 104 94 char *restrict buf); 105 extern char *posix_ctime(const time_t *timer);106 95 extern char *posix_ctime_r(const time_t *timer, char *buf); 107 extern size_t posix_strftime(char *restrict s, size_t maxsize,108 const char *restrict format, const struct tm *restrict tm);109 96 110 97 /* Clocks */ … … 131 118 #define tzset posix_tzset 132 119 133 #define difftime posix_difftime134 135 #define mktime posix_mktime136 #define gmtime posix_gmtime137 120 #define gmtime_r posix_gmtime_r 138 #define localtime posix_localtime139 121 #define localtime_r posix_localtime_r 140 122 141 #define asctime posix_asctime142 123 #define asctime_r posix_asctime_r 143 #define ctime posix_ctime144 124 #define ctime_r posix_ctime_r 145 #define strftime posix_strftime146 125 147 126 #define clock_getres posix_clock_getres
Note:
See TracChangeset
for help on using the changeset viewer.