Changes in uspace/lib/posix/time.c [55b1efd:a12f7f1] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/posix/time.c
r55b1efd ra12f7f1 51 51 #include "libc/sys/time.h" 52 52 53 // TODO: documentation 53 54 // TODO: test everything in this file 54 55 /* In some places in this file, phrase "normalized broken-down time" is used.56 * This means time broken down to components (year, month, day, hour, min, sec),57 * in which every component is in its proper bounds. Non-normalized time could58 * e.g. be 2011-54-5 29:13:-5, which would semantically mean start of year 201159 * + 53 months + 4 days + 29 hours + 13 minutes - 5 seconds.60 */61 62 63 55 64 56 /* Helper functions ***********************************************************/ … … 72 64 73 65 /** 74 * Checks whether the year is a leap year. 75 * 76 * @param year Year since 1900 (e.g. for 1970, the value is 70). 77 * @return true if year is a leap year, false otherwise 66 * 67 * @param year 68 * @return 78 69 */ 79 70 static bool _is_leap_year(time_t year) … … 91 82 92 83 /** 93 * Returns how many days there are in the given month of the given year. 94 * Note that year is only taken into account if month is February. 95 * 96 * @param year Year since 1900 (can be negative). 97 * @param mon Month of the year. 0 for January, 11 for December. 98 * @return Number of days in the specified month. 84 * 85 * @param year 86 * @param mon 87 * @return 99 88 */ 100 89 static int _days_in_month(time_t year, time_t mon) 101 90 { 102 91 assert(mon >= 0 && mon <= 11); 92 year += 1900; 103 93 104 94 static int month_days[] = … … 106 96 107 97 if (mon == 1) { 108 year += 1900;109 98 /* february */ 110 99 return _is_leap_year(year) ? 29 : 28; … … 115 104 116 105 /** 117 * For specified year, month and day of month, returns which day of that year 118 * it is. 119 * 120 * For example, given date 2011-01-03, the corresponding expression is: 121 * _day_of_year(111, 0, 3) == 2 122 * 123 * @param year Year (year 1900 = 0, can be negative). 124 * @param mon Month (January = 0). 125 * @param mday Day of month (First day is 1). 126 * @return Day of year (First day is 0). 106 * 107 * @param year 108 * @param mon 109 * @param mday 110 * @return 127 111 */ 128 112 static int _day_of_year(time_t year, time_t mon, time_t mday) … … 138 122 /** 139 123 * Integer division that rounds to negative infinity. 140 * Used by some functions in this file. 141 * 142 * @param op1 Divident. 143 * @param op2 Divisor. 144 * @return Rounded quotient. 124 * 125 * @param op1 126 * @param op2 127 * @return 145 128 */ 146 129 static time_t _floor_div(time_t op1, time_t op2) … … 155 138 /** 156 139 * Modulo that rounds to negative infinity. 157 * Used by some functions in this file. 158 * 159 * @param op1 Divident. 160 * @param op2 Divisor. 161 * @return Remainder. 140 * 141 * @param op1 142 * @param op2 143 * @return 162 144 */ 163 145 static time_t _floor_mod(time_t op1, time_t op2) … … 179 161 180 162 /** 181 * Number of days since the Epoch. 182 * Epoch is 1970-01-01, which is also equal to day 0. 183 * 184 * @param year Year (year 1900 = 0, may be negative). 185 * @param mon Month (January = 0). 186 * @param mday Day of month (first day = 1). 187 * @return Number of days since the Epoch. 163 * 164 * @param year 165 * @param mon 166 * @param mday 167 * @return 188 168 */ 189 169 static time_t _days_since_epoch(time_t year, time_t mon, time_t mday) … … 195 175 196 176 /** 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.177 * Assumes normalized broken-down time. 178 * 179 * @param tm 180 * @return 201 181 */ 202 182 static time_t _secs_since_epoch(const struct posix_tm *tm) … … 208 188 209 189 /** 210 * Which day of week the specified date is. 211 * 212 * @param year Year (year 1900 = 0). 213 * @param mon Month (January = 0). 214 * @param mday Day of month (first = 1). 215 * @return Day of week (Sunday = 0). 190 * 191 * @param year 192 * @param mon 193 * @param mday 194 * @return 216 195 */ 217 196 static int _day_of_week(time_t year, time_t mon, time_t mday) 218 197 { 219 198 /* 1970-01-01 is Thursday */ 220 return _floor_mod((_days_since_epoch(year, mon, mday) + 4), 7); 221 } 222 223 /** 224 * Normalizes the broken-down time and optionally adds specified amount of 225 * seconds. 226 * 227 * @param tm Broken-down time to normalize. 228 * @param sec_add Seconds to add. 229 * @return 0 on success, -1 on overflow 230 */ 231 static int _normalize_time(struct posix_tm *tm, time_t sec_add) 199 return (_days_since_epoch(year, mon, mday) + 4) % 7; 200 } 201 202 struct _long_tm { 203 time_t tm_sec; 204 time_t tm_min; 205 time_t tm_hour; 206 time_t tm_mday; 207 time_t tm_mon; 208 time_t tm_year; 209 int tm_wday; 210 int tm_yday; 211 int tm_isdst; 212 }; 213 214 /** 215 * 216 * @param ltm 217 * @param ptm 218 */ 219 static void _posix_to_long_tm(struct _long_tm *ltm, struct posix_tm *ptm) 220 { 221 assert(ltm != NULL && ptm != NULL); 222 ltm->tm_sec = ptm->tm_sec; 223 ltm->tm_min = ptm->tm_min; 224 ltm->tm_hour = ptm->tm_hour; 225 ltm->tm_mday = ptm->tm_mday; 226 ltm->tm_mon = ptm->tm_mon; 227 ltm->tm_year = ptm->tm_year; 228 ltm->tm_wday = ptm->tm_wday; 229 ltm->tm_yday = ptm->tm_yday; 230 ltm->tm_isdst = ptm->tm_isdst; 231 } 232 233 /** 234 * 235 * @param ptm 236 * @param ltm 237 */ 238 static void _long_to_posix_tm(struct posix_tm *ptm, struct _long_tm *ltm) 239 { 240 assert(ltm != NULL && ptm != NULL); 241 // FIXME: the cast should be unnecessary, libarch/common.h brain-damage 242 assert((ltm->tm_year >= (int) INT_MIN) && (ltm->tm_year <= (int) INT_MAX)); 243 244 ptm->tm_sec = ltm->tm_sec; 245 ptm->tm_min = ltm->tm_min; 246 ptm->tm_hour = ltm->tm_hour; 247 ptm->tm_mday = ltm->tm_mday; 248 ptm->tm_mon = ltm->tm_mon; 249 ptm->tm_year = ltm->tm_year; 250 ptm->tm_wday = ltm->tm_wday; 251 ptm->tm_yday = ltm->tm_yday; 252 ptm->tm_isdst = ltm->tm_isdst; 253 } 254 255 /** 256 * 257 * @param tm 258 */ 259 static void _normalize_time(struct _long_tm *tm) 232 260 { 233 261 // TODO: DST correction 234 262 235 /* Set initial values. */236 time_t sec = tm->tm_sec + sec_add;237 time_t min = tm->tm_min;238 time_t hour = tm->tm_hour;239 time_t day = tm->tm_mday - 1;240 time_t mon = tm->tm_mon;241 time_t year = tm->tm_year;242 243 263 /* Adjust time. */ 244 min += _floor_div(sec, SECS_PER_MIN);245 sec = _floor_mod(sec, SECS_PER_MIN);246 hour += _floor_div(min, MINS_PER_HOUR);247 min = _floor_mod(min, MINS_PER_HOUR);248 day += _floor_div(hour, HOURS_PER_DAY);249 hour = _floor_mod(hour, HOURS_PER_DAY);264 tm->tm_min += _floor_div(tm->tm_sec, SECS_PER_MIN); 265 tm->tm_sec = _floor_mod(tm->tm_sec, SECS_PER_MIN); 266 tm->tm_hour += _floor_div(tm->tm_min, MINS_PER_HOUR); 267 tm->tm_min = _floor_mod(tm->tm_min, MINS_PER_HOUR); 268 tm->tm_mday += _floor_div(tm->tm_hour, HOURS_PER_DAY); 269 tm->tm_hour = _floor_mod(tm->tm_hour, HOURS_PER_DAY); 250 270 251 271 /* Adjust month. */ 252 year += _floor_div(mon, 12);253 mon = _floor_mod(mon, 12);272 tm->tm_year += _floor_div(tm->tm_mon, 12); 273 tm->tm_mon = _floor_mod(tm->tm_mon, 12); 254 274 255 275 /* Now the difficult part - days of month. */ 256 257 /* First, deal with whole cycles of 400 years = 146097 days. */ 258 year += _floor_div(day, 146097) * 400; 259 day = _floor_mod(day, 146097); 260 261 /* Then, go in one year steps. */ 262 if (mon <= 1) { 263 /* January and February. */ 264 while (day > 365) { 265 day -= _is_leap_year(year) ? 366 : 365; 266 year++; 276 /* Slow, but simple. */ 277 // FIXME: do this faster 278 279 while (tm->tm_mday < 1) { 280 tm->tm_mon--; 281 if (tm->tm_mon == -1) { 282 tm->tm_mon = 11; 283 tm->tm_year--; 267 284 } 268 } else { 269 /* Rest of the year. */ 270 while (day > 365) { 271 day -= _is_leap_year(year + 1) ? 366 : 365; 272 year++; 285 286 tm->tm_mday += _days_in_month(tm->tm_year, tm->tm_mon); 287 } 288 289 while (tm->tm_mday > _days_in_month(tm->tm_year, tm->tm_mon)) { 290 tm->tm_mday -= _days_in_month(tm->tm_year, tm->tm_mon); 291 292 tm->tm_mon++; 293 if (tm->tm_mon == 12) { 294 tm->tm_mon = 0; 295 tm->tm_year++; 273 296 } 274 297 } 275 276 /* Finally, finish it off month per month. */ 277 while (day >= _days_in_month(year, mon)) { 278 day -= _days_in_month(year, mon); 279 mon++; 280 if (mon >= 12) { 281 mon -= 12; 282 year++; 283 } 284 } 285 298 286 299 /* Calculate the remaining two fields. */ 287 tm->tm_yday = _day_of_year(year, mon, day + 1); 288 tm->tm_wday = _day_of_week(year, mon, day + 1); 289 290 /* And put the values back to the struct. */ 291 tm->tm_sec = (int) sec; 292 tm->tm_min = (int) min; 293 tm->tm_hour = (int) hour; 294 tm->tm_mday = (int) day + 1; 295 tm->tm_mon = (int) mon; 296 297 /* Casts to work around libc brain-damage. */ 298 if (year > ((int)INT_MAX) || year < ((int)INT_MIN)) { 299 tm->tm_year = (year < 0) ? ((int)INT_MIN) : ((int)INT_MAX); 300 return -1; 301 } 302 303 tm->tm_year = (int) year; 304 return 0; 305 } 306 307 /** 308 * Which day the week-based year starts on, relative to the first calendar day. 300 tm->tm_yday = _day_of_year(tm->tm_year, tm->tm_mon, tm->tm_mday); 301 tm->tm_wday = _day_of_week(tm->tm_year, tm->tm_mon, tm->tm_mday); 302 } 303 304 /** 305 * Which day the week-based year starts on relative to the first calendar day. 309 306 * E.g. if the year starts on December 31st, the return value is -1. 310 307 * 311 * @param Year since 1900.312 * @return Offset of week-based year relative to calendar year.308 * @param year 309 * @return 313 310 */ 314 311 static int _wbyear_offset(int year) … … 320 317 /** 321 318 * Returns week-based year of the specified time. 322 * 323 * @param tm Normalized broken-down time. 324 * @return Week-based year. 319 * Assumes normalized broken-down time. 320 * 321 * @param tm 322 * @return 325 323 */ 326 324 static int _wbyear(const struct posix_tm *tm) … … 331 329 return tm->tm_year - 1; 332 330 } 333 if (day > 364 + _is_leap_year(tm->tm_year)) 331 if (day > 364 + _is_leap_year(tm->tm_year)){ 334 332 /* First week of next year. */ 335 333 return tm->tm_year + 1; … … 370 368 return 53; 371 369 } 372 if (day > 364 + _is_leap_year(tm->tm_year)) 370 if (day > 364 + _is_leap_year(tm->tm_year)){ 373 371 /* First week of next year. */ 374 372 return 1; … … 399 397 400 398 /** 401 * Set timezone conversion information.399 * 402 400 */ 403 401 void posix_tzset(void) … … 411 409 412 410 /** 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. 411 * 412 * @param time1 413 * @param time0 414 * @return 418 415 */ 419 416 double posix_difftime(time_t time1, time_t time0) … … 428 425 * 429 426 * @param tm Broken-down time. 430 * @return time_t representation of the time, undefined value on overflow .427 * @return time_t representation of the time, undefined value on overflow 431 428 */ 432 429 time_t posix_mktime(struct posix_tm *tm) … … 435 432 // TODO: detect overflow 436 433 437 _normalize_time(tm, 0); 434 struct _long_tm ltm; 435 _posix_to_long_tm(<m, tm); 436 _normalize_time(<m); 437 _long_to_posix_tm(tm, <m); 438 438 439 return _secs_since_epoch(tm); 439 440 } 440 441 441 442 /** 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. 443 * 444 * @param timer 445 * @return 446 446 */ 447 447 struct posix_tm *posix_gmtime(const time_t *timer) 448 448 { 449 assert(timer != NULL);450 451 449 static struct posix_tm result; 452 450 return posix_gmtime_r(timer, &result); … … 454 452 455 453 /** 456 * Converts a time value to a broken-down UTC time. 457 * 458 * @param timer Time to convert. 459 * @param result Structure to store the result to. 460 * @return Value of result on success, NULL on overflow. 454 * 455 * @param timer 456 * @param result 457 * @return 461 458 */ 462 459 struct posix_tm *posix_gmtime_r(const time_t *restrict timer, … … 466 463 assert(result != NULL); 467 464 468 /* Set result to epoch. */ 469 result->tm_sec = 0; 470 result->tm_min = 0; 471 result->tm_hour = 0; 472 result->tm_mday = 1; 473 result->tm_mon = 0; 474 result->tm_year = 70; /* 1970 */ 475 476 if (_normalize_time(result, *timer) == -1) { 465 /* Set epoch and seconds to _long_tm struct and normalize to get 466 * correct values. 467 */ 468 struct _long_tm ltm = { 469 .tm_sec = *timer, 470 .tm_min = 0, 471 .tm_hour = 0, /* 00:00:xx */ 472 .tm_mday = 1, 473 .tm_mon = 0, /* January 1st */ 474 .tm_year = 70, /* 1970 */ 475 }; 476 _normalize_time(<m); 477 478 if (ltm.tm_year < (int) INT_MIN || ltm.tm_year > (int) INT_MAX) { 477 479 errno = EOVERFLOW; 478 480 return NULL; 479 481 } 480 482 483 _long_to_posix_tm(result, <m); 481 484 return result; 482 485 } 483 486 484 487 /** 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. 488 * 489 * @param timer 490 * @return 489 491 */ 490 492 struct posix_tm *posix_localtime(const time_t *timer) … … 495 497 496 498 /** 497 * Converts a time value to a broken-down local time. 498 * 499 * @param timer Time to convert. 500 * @param result Structure to store the result to. 501 * @return Value of result on success, NULL on overflow. 499 * 500 * @param timer 501 * @param result 502 * @return 502 503 */ 503 504 struct posix_tm *posix_localtime_r(const time_t *restrict timer, … … 510 511 511 512 /** 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. 513 * 514 * @param timeptr 515 * @return 517 516 */ 518 517 char *posix_asctime(const struct posix_tm *timeptr) … … 523 522 524 523 /** 525 * Converts broken-down time to a string in format 526 * "Sun Jan 1 00:00:00 1970\n". (Obsolete) 527 * 528 * @param timeptr Broken-down time structure. 529 * @param buf Buffer to store string to, must be at least ASCTIME_BUF_LEN 530 * bytes long. 531 * @return Value of buf. 524 * 525 * @param timeptr 526 * @param buf 527 * @return 532 528 */ 533 529 char *posix_asctime_r(const struct posix_tm *restrict timeptr, … … 556 552 557 553 /** 558 * Equivalent to asctime(localtime(clock)). 559 * 560 * @param timer Time to convert. 561 * @return Pointer to a statically allocated string holding the date. 554 * 555 * @param timer 556 * @return 562 557 */ 563 558 char *posix_ctime(const time_t *timer) … … 571 566 572 567 /** 573 * Reentrant variant of ctime(). 574 * 575 * @param timer Time to convert. 576 * @param buf Buffer to store string to. Must be at least ASCTIME_BUF_LEN 577 * bytes long. 578 * @return Pointer to buf on success, NULL on falure. 568 * 569 * @param timer 570 * @param buf 571 * @return 579 572 */ 580 573 char *posix_ctime_r(const time_t *timer, char *buf) … … 588 581 589 582 /** 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. 583 * 584 * @param s 585 * @param maxsize 586 * @param format 587 * @param tm 588 * @return 598 589 */ 599 590 size_t posix_strftime(char *restrict s, size_t maxsize, 600 591 const char *restrict format, const struct posix_tm *restrict tm) 601 592 { 602 assert(s != NULL);603 assert(format != NULL);604 assert(tm != NULL);605 606 593 // TODO: use locale 607 594 static const char *wday_abbr[] = { … … 780 767 781 768 /** 782 * Get clock resolution. Only CLOCK_REALTIME is supported. 783 * 784 * @param clock_id Clock ID. 785 * @param res Pointer to the variable where the resolution is to be written. 786 * @return 0 on success, -1 with errno set on failure. 769 * 770 * @param s 771 * @param maxsize 772 * @param format 773 * @param tm 774 * @param loc 775 * @return 776 */ 777 extern size_t posix_strftime_l(char *restrict s, size_t maxsize, 778 const char *restrict format, const struct posix_tm *restrict tm, 779 posix_locale_t loc) 780 { 781 // TODO 782 not_implemented(); 783 } 784 785 /** 786 * 787 * @param clock_id 788 * @param res 789 * @return 787 790 */ 788 791 int posix_clock_getres(posix_clockid_t clock_id, struct posix_timespec *res) … … 802 805 803 806 /** 804 * Get time. Only CLOCK_REALTIME is supported. 805 * 806 * @param clock_id ID of the clock to query. 807 * @param tp Pointer to the variable where the time is to be written. 808 * @return 0 on success, -1 with errno on failure. 807 * 808 * @param clock_id 809 * @param tp 810 * @return 809 811 */ 810 812 int posix_clock_gettime(posix_clockid_t clock_id, struct posix_timespec *tp) … … 827 829 828 830 /** 829 * Set time on a specified clock. As HelenOS doesn't support this yet, 830 * this function always fails. 831 * 832 * @param clock_id ID of the clock to set. 833 * @param tp Time to set. 834 * @return 0 on success, -1 with errno on failure. 831 * 832 * @param clock_id 833 * @param tp 834 * @return 835 835 */ 836 836 int posix_clock_settime(posix_clockid_t clock_id, … … 853 853 854 854 /** 855 * Sleep on a specified clock. 856 * 857 * @param clock_id ID of the clock to sleep on (only CLOCK_REALTIME supported). 858 * @param flags Flags (none supported). 859 * @param rqtp Sleep time. 860 * @param rmtp Remaining time is written here if sleep is interrupted. 861 * @return 0 on success, -1 with errno set on failure. 855 * 856 * @param clock_id 857 * @param flags 858 * @param rqtp 859 * @param rmtp 860 * @return 862 861 */ 863 862 int posix_clock_nanosleep(posix_clockid_t clock_id, int flags, … … 883 882 } 884 883 884 #if 0 885 886 struct __posix_timer { 887 posix_clockid_t clockid; 888 struct posix_sigevent evp; 889 }; 890 891 /** 892 * 893 * @param clockid 894 * @param evp 895 * @param timerid 896 * @return 897 */ 898 int posix_timer_create(posix_clockid_t clockid, 899 struct posix_sigevent *restrict evp, 900 posix_timer_t *restrict timerid) 901 { 902 // TODO 903 not_implemented(); 904 } 905 906 /** 907 * 908 * @param timerid 909 * @return 910 */ 911 int posix_timer_delete(posix_timer_t timerid) 912 { 913 // TODO 914 not_implemented(); 915 } 916 917 /** 918 * 919 * @param timerid 920 * @return 921 */ 922 int posix_timer_getoverrun(posix_timer_t timerid) 923 { 924 // TODO 925 not_implemented(); 926 } 927 928 /** 929 * 930 * @param timerid 931 * @param value 932 * @return 933 */ 934 int posix_timer_gettime(posix_timer_t timerid, 935 struct posix_itimerspec *value) 936 { 937 // TODO 938 not_implemented(); 939 } 940 941 /** 942 * 943 * @param timerid 944 * @param flags 945 * @param value 946 * @param ovalue 947 * @return 948 */ 949 int posix_timer_settime(posix_timer_t timerid, int flags, 950 const struct posix_itimerspec *restrict value, 951 struct posix_itimerspec *restrict ovalue) 952 { 953 // TODO 954 not_implemented(); 955 } 956 957 #endif 958 885 959 /** 886 960 * Get CPU time used since the process invocation.
Note:
See TracChangeset
for help on using the changeset viewer.