Changeset c2b0e10 in mainline
- Timestamp:
- 2012-04-23T21:42:27Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 5b3394c
- Parents:
- cb948777
- Location:
- uspace/lib
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/time.c
rcb948777 rc2b0e10 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> 45 50 46 51 /** Pointer to kernel shared variables with time */ … … 50 55 volatile sysarg_t seconds2; 51 56 } *ktime = NULL; 57 58 /* Helper functions ***********************************************************/ 59 60 #define HOURS_PER_DAY (24) 61 #define MINS_PER_HOUR (60) 62 #define SECS_PER_MIN (60) 63 #define MINS_PER_DAY (MINS_PER_HOUR * HOURS_PER_DAY) 64 #define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR) 65 #define SECS_PER_DAY (SECS_PER_HOUR * HOURS_PER_DAY) 66 67 /** 68 * Checks whether the year is a leap year. 69 * 70 * @param year Year since 1900 (e.g. for 1970, the value is 70). 71 * @return true if year is a leap year, false otherwise 72 */ 73 static bool _is_leap_year(time_t year) 74 { 75 year += 1900; 76 77 if (year % 400 == 0) 78 return true; 79 if (year % 100 == 0) 80 return false; 81 if (year % 4 == 0) 82 return true; 83 return false; 84 } 85 86 /** 87 * Returns how many days there are in the given month of the given year. 88 * Note that year is only taken into account if month is February. 89 * 90 * @param year Year since 1900 (can be negative). 91 * @param mon Month of the year. 0 for January, 11 for December. 92 * @return Number of days in the specified month. 93 */ 94 static int _days_in_month(time_t year, time_t mon) 95 { 96 assert(mon >= 0 && mon <= 11); 97 98 static int month_days[] = 99 { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 100 101 if (mon == 1) { 102 year += 1900; 103 /* february */ 104 return _is_leap_year(year) ? 29 : 28; 105 } else { 106 return month_days[mon]; 107 } 108 } 109 110 /** 111 * For specified year, month and day of month, returns which day of that year 112 * it is. 113 * 114 * For example, given date 2011-01-03, the corresponding expression is: 115 * _day_of_year(111, 0, 3) == 2 116 * 117 * @param year Year (year 1900 = 0, can be negative). 118 * @param mon Month (January = 0). 119 * @param mday Day of month (First day is 1). 120 * @return Day of year (First day is 0). 121 */ 122 static int _day_of_year(time_t year, time_t mon, time_t mday) 123 { 124 static int mdays[] = 125 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; 126 static int leap_mdays[] = 127 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }; 128 129 return (_is_leap_year(year) ? leap_mdays[mon] : mdays[mon]) + mday - 1; 130 } 131 132 /** 133 * Integer division that rounds to negative infinity. 134 * Used by some functions in this file. 135 * 136 * @param op1 Dividend. 137 * @param op2 Divisor. 138 * @return Rounded quotient. 139 */ 140 static time_t _floor_div(time_t op1, time_t op2) 141 { 142 if (op1 >= 0 || op1 % op2 == 0) { 143 return op1 / op2; 144 } else { 145 return op1 / op2 - 1; 146 } 147 } 148 149 /** 150 * Modulo that rounds to negative infinity. 151 * Used by some functions in this file. 152 * 153 * @param op1 Dividend. 154 * @param op2 Divisor. 155 * @return Remainder. 156 */ 157 static time_t _floor_mod(time_t op1, time_t op2) 158 { 159 int div = _floor_div(op1, op2); 160 161 /* (a / b) * b + a % b == a */ 162 /* thus, a % b == a - (a / b) * b */ 163 164 int result = op1 - div * op2; 165 166 /* Some paranoid checking to ensure I didn't make a mistake here. */ 167 assert(result >= 0); 168 assert(result < op2); 169 assert(div * op2 + result == op1); 170 171 return result; 172 } 173 174 /** 175 * Number of days since the Epoch. 176 * Epoch is 1970-01-01, which is also equal to day 0. 177 * 178 * @param year Year (year 1900 = 0, may be negative). 179 * @param mon Month (January = 0). 180 * @param mday Day of month (first day = 1). 181 * @return Number of days since the Epoch. 182 */ 183 static time_t _days_since_epoch(time_t year, time_t mon, time_t mday) 184 { 185 return (year - 70) * 365 + _floor_div(year - 69, 4) - 186 _floor_div(year - 1, 100) + _floor_div(year + 299, 400) + 187 _day_of_year(year, mon, mday); 188 } 189 190 /** 191 * Seconds since the Epoch. see also _days_since_epoch(). 192 * 193 * @param tm Normalized broken-down time. 194 * @return Number of seconds since the epoch, not counting leap seconds. 195 */ 196 static time_t _secs_since_epoch(const struct tm *tm) 197 { 198 return _days_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday) * 199 SECS_PER_DAY + tm->tm_hour * SECS_PER_HOUR + 200 tm->tm_min * SECS_PER_MIN + tm->tm_sec; 201 } 202 203 /** 204 * Which day of week the specified date is. 205 * 206 * @param year Year (year 1900 = 0). 207 * @param mon Month (January = 0). 208 * @param mday Day of month (first = 1). 209 * @return Day of week (Sunday = 0). 210 */ 211 static int _day_of_week(time_t year, time_t mon, time_t mday) 212 { 213 /* 1970-01-01 is Thursday */ 214 return _floor_mod((_days_since_epoch(year, mon, mday) + 4), 7); 215 } 216 217 /** 218 * Normalizes the broken-down time and optionally adds specified amount of 219 * seconds. 220 * 221 * @param tm Broken-down time to normalize. 222 * @param sec_add Seconds to add. 223 * @return 0 on success, -1 on overflow 224 */ 225 static int _normalize_time(struct tm *tm, time_t sec_add) 226 { 227 // TODO: DST correction 228 229 /* Set initial values. */ 230 time_t sec = tm->tm_sec + sec_add; 231 time_t min = tm->tm_min; 232 time_t hour = tm->tm_hour; 233 time_t day = tm->tm_mday - 1; 234 time_t mon = tm->tm_mon; 235 time_t year = tm->tm_year; 236 237 /* Adjust time. */ 238 min += _floor_div(sec, SECS_PER_MIN); 239 sec = _floor_mod(sec, SECS_PER_MIN); 240 hour += _floor_div(min, MINS_PER_HOUR); 241 min = _floor_mod(min, MINS_PER_HOUR); 242 day += _floor_div(hour, HOURS_PER_DAY); 243 hour = _floor_mod(hour, HOURS_PER_DAY); 244 245 /* Adjust month. */ 246 year += _floor_div(mon, 12); 247 mon = _floor_mod(mon, 12); 248 249 /* Now the difficult part - days of month. */ 250 251 /* First, deal with whole cycles of 400 years = 146097 days. */ 252 year += _floor_div(day, 146097) * 400; 253 day = _floor_mod(day, 146097); 254 255 /* Then, go in one year steps. */ 256 if (mon <= 1) { 257 /* January and February. */ 258 while (day > 365) { 259 day -= _is_leap_year(year) ? 366 : 365; 260 year++; 261 } 262 } else { 263 /* Rest of the year. */ 264 while (day > 365) { 265 day -= _is_leap_year(year + 1) ? 366 : 365; 266 year++; 267 } 268 } 269 270 /* Finally, finish it off month per month. */ 271 while (day >= _days_in_month(year, mon)) { 272 day -= _days_in_month(year, mon); 273 mon++; 274 if (mon >= 12) { 275 mon -= 12; 276 year++; 277 } 278 } 279 280 /* Calculate the remaining two fields. */ 281 tm->tm_yday = _day_of_year(year, mon, day + 1); 282 tm->tm_wday = _day_of_week(year, mon, day + 1); 283 284 /* And put the values back to the struct. */ 285 tm->tm_sec = (int) sec; 286 tm->tm_min = (int) min; 287 tm->tm_hour = (int) hour; 288 tm->tm_mday = (int) day + 1; 289 tm->tm_mon = (int) mon; 290 291 /* Casts to work around libc brain-damage. */ 292 if (year > ((int)INT_MAX) || year < ((int)INT_MIN)) { 293 tm->tm_year = (year < 0) ? ((int)INT_MIN) : ((int)INT_MAX); 294 return -1; 295 } 296 297 tm->tm_year = (int) year; 298 return 0; 299 } 300 301 /** 302 * Which day the week-based year starts on, relative to the first calendar day. 303 * E.g. if the year starts on December 31st, the return value is -1. 304 * 305 * @param Year since 1900. 306 * @return Offset of week-based year relative to calendar year. 307 */ 308 static int _wbyear_offset(int year) 309 { 310 int start_wday = _day_of_week(year, 0, 1); 311 return _floor_mod(4 - start_wday, 7) - 3; 312 } 313 314 /** 315 * Returns week-based year of the specified time. 316 * 317 * @param tm Normalized broken-down time. 318 * @return Week-based year. 319 */ 320 static int _wbyear(const struct tm *tm) 321 { 322 int day = tm->tm_yday - _wbyear_offset(tm->tm_year); 323 if (day < 0) { 324 /* Last week of previous year. */ 325 return tm->tm_year - 1; 326 } 327 if (day > 364 + _is_leap_year(tm->tm_year)) { 328 /* First week of next year. */ 329 return tm->tm_year + 1; 330 } 331 /* All the other days are in the calendar year. */ 332 return tm->tm_year; 333 } 334 335 /** 336 * Week number of the year, assuming weeks start on sunday. 337 * The first Sunday of January is the first day of week 1; 338 * days in the new year before this are in week 0. 339 * 340 * @param tm Normalized broken-down time. 341 * @return The week number (0 - 53). 342 */ 343 static int _sun_week_number(const struct tm *tm) 344 { 345 int first_day = (7 - _day_of_week(tm->tm_year, 0, 1)) % 7; 346 return (tm->tm_yday - first_day + 7) / 7; 347 } 348 349 /** 350 * Week number of the year, assuming weeks start on monday. 351 * If the week containing January 1st has four or more days in the new year, 352 * then it is considered week 1. Otherwise, it is the last week of the previous 353 * year, and the next week is week 1. Both January 4th and the first Thursday 354 * of January are always in week 1. 355 * 356 * @param tm Normalized broken-down time. 357 * @return The week number (1 - 53). 358 */ 359 static int _iso_week_number(const struct tm *tm) 360 { 361 int day = tm->tm_yday - _wbyear_offset(tm->tm_year); 362 if (day < 0) { 363 /* Last week of previous year. */ 364 return 53; 365 } 366 if (day > 364 + _is_leap_year(tm->tm_year)) { 367 /* First week of next year. */ 368 return 1; 369 } 370 /* All the other days give correct answer. */ 371 return (day / 7 + 1); 372 } 373 374 /** 375 * Week number of the year, assuming weeks start on monday. 376 * The first Monday of January is the first day of week 1; 377 * days in the new year before this are in week 0. 378 * 379 * @param tm Normalized broken-down time. 380 * @return The week number (0 - 53). 381 */ 382 static int _mon_week_number(const struct tm *tm) 383 { 384 int first_day = (1 - _day_of_week(tm->tm_year, 0, 1)) % 7; 385 return (tm->tm_yday - first_day + 7) / 7; 386 } 387 388 /******************************************************************************/ 389 52 390 53 391 /** Add microseconds to given timeval. … … 228 566 } 229 567 568 /** 569 * This function first normalizes the provided broken-down time 570 * (moves all values to their proper bounds) and then tries to 571 * calculate the appropriate time_t representation. 572 * 573 * @param tm Broken-down time. 574 * @return time_t representation of the time, undefined value on overflow. 575 */ 576 time_t mktime(struct tm *tm) 577 { 578 // TODO: take DST flag into account 579 // TODO: detect overflow 580 581 _normalize_time(tm, 0); 582 return _secs_since_epoch(tm); 583 } 584 585 /** 586 * Convert time and date to a string, based on a specified format and 587 * current locale. 588 * 589 * @param s Buffer to write string to. 590 * @param maxsize Size of the buffer. 591 * @param format Format of the output. 592 * @param tm Broken-down time to format. 593 * @return Number of bytes written. 594 */ 595 size_t strftime(char *restrict s, size_t maxsize, 596 const char *restrict format, const struct tm *restrict tm) 597 { 598 assert(s != NULL); 599 assert(format != NULL); 600 assert(tm != NULL); 601 602 // TODO: use locale 603 static const char *wday_abbr[] = { 604 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 605 }; 606 static const char *wday[] = { 607 "Sunday", "Monday", "Tuesday", "Wednesday", 608 "Thursday", "Friday", "Saturday" 609 }; 610 static const char *mon_abbr[] = { 611 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 612 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 613 }; 614 static const char *mon[] = { 615 "January", "February", "March", "April", "May", "June", "July", 616 "August", "September", "October", "November", "December" 617 }; 618 619 if (maxsize < 1) { 620 return 0; 621 } 622 623 char *ptr = s; 624 size_t consumed; 625 size_t remaining = maxsize; 626 627 #define append(...) { \ 628 /* FIXME: this requires POSIX-correct snprintf */ \ 629 /* otherwise it won't work with non-ascii chars */ \ 630 consumed = snprintf(ptr, remaining, __VA_ARGS__); \ 631 if (consumed >= remaining) { \ 632 return 0; \ 633 } \ 634 ptr += consumed; \ 635 remaining -= consumed; \ 636 } 637 638 #define recurse(fmt) { \ 639 consumed = strftime(ptr, remaining, fmt, tm); \ 640 if (consumed == 0) { \ 641 return 0; \ 642 } \ 643 ptr += consumed; \ 644 remaining -= consumed; \ 645 } 646 647 #define TO_12H(hour) (((hour) > 12) ? ((hour) - 12) : \ 648 (((hour) == 0) ? 12 : (hour))) 649 650 while (*format != '\0') { 651 if (*format != '%') { 652 append("%c", *format); 653 format++; 654 continue; 655 } 656 657 format++; 658 if (*format == '0' || *format == '+') { 659 // TODO: padding 660 format++; 661 } 662 while (isdigit(*format)) { 663 // TODO: padding 664 format++; 665 } 666 if (*format == 'O' || *format == 'E') { 667 // TODO: locale's alternative format 668 format++; 669 } 670 671 switch (*format) { 672 case 'a': 673 append("%s", wday_abbr[tm->tm_wday]); break; 674 case 'A': 675 append("%s", wday[tm->tm_wday]); break; 676 case 'b': 677 append("%s", mon_abbr[tm->tm_mon]); break; 678 case 'B': 679 append("%s", mon[tm->tm_mon]); break; 680 case 'c': 681 // TODO: locale-specific datetime format 682 recurse("%Y-%m-%d %H:%M:%S"); break; 683 case 'C': 684 append("%02d", (1900 + tm->tm_year) / 100); break; 685 case 'd': 686 append("%02d", tm->tm_mday); break; 687 case 'D': 688 recurse("%m/%d/%y"); break; 689 case 'e': 690 append("%2d", tm->tm_mday); break; 691 case 'F': 692 recurse("%+4Y-%m-%d"); break; 693 case 'g': 694 append("%02d", _wbyear(tm) % 100); break; 695 case 'G': 696 append("%d", _wbyear(tm)); break; 697 case 'h': 698 recurse("%b"); break; 699 case 'H': 700 append("%02d", tm->tm_hour); break; 701 case 'I': 702 append("%02d", TO_12H(tm->tm_hour)); break; 703 case 'j': 704 append("%03d", tm->tm_yday); break; 705 case 'k': 706 append("%2d", tm->tm_hour); break; 707 case 'l': 708 append("%2d", TO_12H(tm->tm_hour)); break; 709 case 'm': 710 append("%02d", tm->tm_mon); break; 711 case 'M': 712 append("%02d", tm->tm_min); break; 713 case 'n': 714 append("\n"); break; 715 case 'p': 716 append("%s", tm->tm_hour < 12 ? "AM" : "PM"); break; 717 case 'P': 718 append("%s", tm->tm_hour < 12 ? "am" : "PM"); break; 719 case 'r': 720 recurse("%I:%M:%S %p"); break; 721 case 'R': 722 recurse("%H:%M"); break; 723 case 's': 724 append("%ld", _secs_since_epoch(tm)); break; 725 case 'S': 726 append("%02d", tm->tm_sec); break; 727 case 't': 728 append("\t"); break; 729 case 'T': 730 recurse("%H:%M:%S"); break; 731 case 'u': 732 append("%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday); 733 break; 734 case 'U': 735 append("%02d", _sun_week_number(tm)); break; 736 case 'V': 737 append("%02d", _iso_week_number(tm)); break; 738 case 'w': 739 append("%d", tm->tm_wday); break; 740 case 'W': 741 append("%02d", _mon_week_number(tm)); break; 742 case 'x': 743 // TODO: locale-specific date format 744 recurse("%Y-%m-%d"); break; 745 case 'X': 746 // TODO: locale-specific time format 747 recurse("%H:%M:%S"); break; 748 case 'y': 749 append("%02d", tm->tm_year % 100); break; 750 case 'Y': 751 append("%d", 1900 + tm->tm_year); break; 752 case 'z': 753 // TODO: timezone 754 break; 755 case 'Z': 756 // TODO: timezone 757 break; 758 case '%': 759 append("%%"); 760 break; 761 default: 762 /* Invalid specifier, print verbatim. */ 763 while (*format != '%') { 764 format--; 765 } 766 append("%%"); 767 break; 768 } 769 format++; 770 } 771 772 #undef append 773 #undef recurse 774 775 return maxsize - remaining; 776 } 777 778 230 779 /** @} 231 780 */ -
uspace/lib/c/include/sys/time.h
rcb948777 rc2b0e10 77 77 78 78 extern void udelay(useconds_t); 79 extern time_t mktime(struct tm *tm); 80 extern size_t strftime(char *restrict s, size_t maxsize, 81 const char *restrict format, const struct tm *restrict tm); 79 82 80 83 #endif -
uspace/lib/posix/time.c
rcb948777 rc2b0e10 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 … … 420 320 { 421 321 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 322 } 440 323 … … 585 468 } 586 469 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);737 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 470 } 781 471 -
uspace/lib/posix/time.h
rcb948777 rc2b0e10 91 91 92 92 /* Broken-down Time */ 93 extern time_t posix_mktime(struct tm *tm);94 93 extern struct tm *posix_gmtime(const time_t *timer); 95 94 extern struct tm *posix_gmtime_r(const time_t *restrict timer, … … 105 104 extern char *posix_ctime(const time_t *timer); 106 105 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 106 110 107 /* Clocks */ … … 133 130 #define difftime posix_difftime 134 131 135 #define mktime posix_mktime136 132 #define gmtime posix_gmtime 137 133 #define gmtime_r posix_gmtime_r … … 143 139 #define ctime posix_ctime 144 140 #define ctime_r posix_ctime_r 145 #define strftime posix_strftime146 141 147 142 #define clock_getres posix_clock_getres
Note:
See TracChangeset
for help on using the changeset viewer.