Changeset 1d2a1a9 in mainline for uspace/lib/posix/time.c
- Timestamp:
- 2011-08-17T20:44:32Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 0cc32f2
- Parents:
- bb285b4 (diff), c53a705 (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. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/posix/time.c
rbb285b4 r1d2a1a9 51 51 #include "libc/sys/time.h" 52 52 53 // TODO: documentation54 53 // 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 could 58 * e.g. be 2011-54-5 29:13:-5, which would semantically mean start of year 2011 59 * + 53 months + 4 days + 29 hours + 13 minutes - 5 seconds. 60 */ 61 62 55 63 56 64 /* Helper functions ***********************************************************/ … … 64 72 65 73 /** 66 * 67 * @param year 68 * @return 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 69 78 */ 70 79 static bool _is_leap_year(time_t year) … … 82 91 83 92 /** 84 * 85 * @param year 86 * @param mon 87 * @return 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. 88 99 */ 89 100 static int _days_in_month(time_t year, time_t mon) 90 101 { 91 102 assert(mon >= 0 && mon <= 11); 92 year += 1900;93 103 94 104 static int month_days[] = … … 96 106 97 107 if (mon == 1) { 108 year += 1900; 98 109 /* february */ 99 110 return _is_leap_year(year) ? 29 : 28; … … 104 115 105 116 /** 106 * 107 * @param year 108 * @param mon 109 * @param mday 110 * @return 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). 111 127 */ 112 128 static int _day_of_year(time_t year, time_t mon, time_t mday) … … 122 138 /** 123 139 * Integer division that rounds to negative infinity. 124 * 125 * @param op1 126 * @param op2 127 * @return 140 * Used by some functions in this file. 141 * 142 * @param op1 Divident. 143 * @param op2 Divisor. 144 * @return Rounded quotient. 128 145 */ 129 146 static time_t _floor_div(time_t op1, time_t op2) … … 138 155 /** 139 156 * Modulo that rounds to negative infinity. 140 * 141 * @param op1 142 * @param op2 143 * @return 157 * Used by some functions in this file. 158 * 159 * @param op1 Divident. 160 * @param op2 Divisor. 161 * @return Remainder. 144 162 */ 145 163 static time_t _floor_mod(time_t op1, time_t op2) … … 161 179 162 180 /** 163 * 164 * @param year 165 * @param mon 166 * @param mday 167 * @return 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. 168 188 */ 169 189 static time_t _days_since_epoch(time_t year, time_t mon, time_t mday) … … 175 195 176 196 /** 177 * Assumes normalized broken-down time.178 * 179 * @param tm 180 * @return 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. 181 201 */ 182 202 static time_t _secs_since_epoch(const struct posix_tm *tm) … … 188 208 189 209 /** 190 * 191 * @param year 192 * @param mon 193 * @param mday 194 * @return 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). 195 216 */ 196 217 static int _day_of_week(time_t year, time_t mon, time_t mday) 197 218 { 198 219 /* 1970-01-01 is Thursday */ 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) 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) 260 232 { 261 233 // TODO: DST correction 262 234 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 263 243 /* Adjust time. */ 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);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); 270 250 271 251 /* Adjust month. */ 272 tm->tm_year += _floor_div(tm->tm_mon, 12);273 tm->tm_mon = _floor_mod(tm->tm_mon, 12);252 year += _floor_div(mon, 12); 253 mon = _floor_mod(mon, 12); 274 254 275 255 /* Now the difficult part - days of month. */ 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--; 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++; 284 267 } 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++; 268 } else { 269 /* Rest of the year. */ 270 while (day > 365) { 271 day -= _is_leap_year(year + 1) ? 366 : 365; 272 year++; 296 273 } 297 274 } 298 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 299 286 /* Calculate the remaining two fields. */ 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. 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. 306 309 * E.g. if the year starts on December 31st, the return value is -1. 307 310 * 308 * @param year309 * @return 311 * @param Year since 1900. 312 * @return Offset of week-based year relative to calendar year. 310 313 */ 311 314 static int _wbyear_offset(int year) … … 317 320 /** 318 321 * Returns week-based year of the specified time. 319 * Assumes normalized broken-down time. 320 * 321 * @param tm 322 * @return 322 * 323 * @param tm Normalized broken-down time. 324 * @return Week-based year. 323 325 */ 324 326 static int _wbyear(const struct posix_tm *tm) … … 329 331 return tm->tm_year - 1; 330 332 } 331 if (day > 364 + _is_leap_year(tm->tm_year)) {333 if (day > 364 + _is_leap_year(tm->tm_year)) { 332 334 /* First week of next year. */ 333 335 return tm->tm_year + 1; … … 368 370 return 53; 369 371 } 370 if (day > 364 + _is_leap_year(tm->tm_year)) {372 if (day > 364 + _is_leap_year(tm->tm_year)) { 371 373 /* First week of next year. */ 372 374 return 1; … … 397 399 398 400 /** 399 * 401 * Set timezone conversion information. 400 402 */ 401 403 void posix_tzset(void) … … 409 411 410 412 /** 411 * 412 * @param time1 413 * @param time0 414 * @return 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. 415 418 */ 416 419 double posix_difftime(time_t time1, time_t time0) … … 425 428 * 426 429 * @param tm Broken-down time. 427 * @return time_t representation of the time, undefined value on overflow 430 * @return time_t representation of the time, undefined value on overflow. 428 431 */ 429 432 time_t posix_mktime(struct posix_tm *tm) … … 432 435 // TODO: detect overflow 433 436 434 struct _long_tm ltm; 435 _posix_to_long_tm(<m, tm); 436 _normalize_time(<m); 437 _long_to_posix_tm(tm, <m); 438 437 _normalize_time(tm, 0); 439 438 return _secs_since_epoch(tm); 440 439 } 441 440 442 441 /** 443 * 444 * @param timer 445 * @return 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 446 */ 447 447 struct posix_tm *posix_gmtime(const time_t *timer) 448 448 { 449 assert(timer != NULL); 450 449 451 static struct posix_tm result; 450 452 return posix_gmtime_r(timer, &result); … … 452 454 453 455 /** 454 * 455 * @param timer 456 * @param result 457 * @return 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. 458 461 */ 459 462 struct posix_tm *posix_gmtime_r(const time_t *restrict timer, … … 463 466 assert(result != NULL); 464 467 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) { 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) { 479 477 errno = EOVERFLOW; 480 478 return NULL; 481 479 } 482 480 483 _long_to_posix_tm(result, <m);484 481 return result; 485 482 } 486 483 487 484 /** 488 * 489 * @param timer 490 * @return 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. 491 489 */ 492 490 struct posix_tm *posix_localtime(const time_t *timer) … … 497 495 498 496 /** 499 * 500 * @param timer 501 * @param result 502 * @return 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. 503 502 */ 504 503 struct posix_tm *posix_localtime_r(const time_t *restrict timer, … … 511 510 512 511 /** 513 * 514 * @param timeptr 515 * @return 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. 516 517 */ 517 518 char *posix_asctime(const struct posix_tm *timeptr) … … 522 523 523 524 /** 524 * 525 * @param timeptr 526 * @param buf 527 * @return 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. 528 532 */ 529 533 char *posix_asctime_r(const struct posix_tm *restrict timeptr, … … 552 556 553 557 /** 554 * 555 * @param timer 556 * @return 558 * Equivalent to asctime(localtime(clock)). 559 * 560 * @param timer Time to convert. 561 * @return Pointer to a statically allocated string holding the date. 557 562 */ 558 563 char *posix_ctime(const time_t *timer) … … 566 571 567 572 /** 568 * 569 * @param timer 570 * @param buf 571 * @return 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. 572 579 */ 573 580 char *posix_ctime_r(const time_t *timer, char *buf) … … 581 588 582 589 /** 583 * 584 * @param s 585 * @param maxsize 586 * @param format 587 * @param tm 588 * @return 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. 589 598 */ 590 599 size_t posix_strftime(char *restrict s, size_t maxsize, 591 600 const char *restrict format, const struct posix_tm *restrict tm) 592 601 { 602 assert(s != NULL); 603 assert(format != NULL); 604 assert(tm != NULL); 605 593 606 // TODO: use locale 594 607 static const char *wday_abbr[] = { … … 767 780 768 781 /** 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 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. 790 787 */ 791 788 int posix_clock_getres(posix_clockid_t clock_id, struct posix_timespec *res) … … 805 802 806 803 /** 807 * 808 * @param clock_id 809 * @param tp 810 * @return 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. 811 809 */ 812 810 int posix_clock_gettime(posix_clockid_t clock_id, struct posix_timespec *tp) … … 829 827 830 828 /** 831 * 832 * @param clock_id 833 * @param tp 834 * @return 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. 835 835 */ 836 836 int posix_clock_settime(posix_clockid_t clock_id, … … 853 853 854 854 /** 855 * 856 * @param clock_id 857 * @param flags 858 * @param rqtp 859 * @param rmtp 860 * @return 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. 861 862 */ 862 863 int posix_clock_nanosleep(posix_clockid_t clock_id, int flags, … … 882 883 } 883 884 884 #if 0885 886 struct __posix_timer {887 posix_clockid_t clockid;888 struct posix_sigevent evp;889 };890 891 /**892 *893 * @param clockid894 * @param evp895 * @param timerid896 * @return897 */898 int posix_timer_create(posix_clockid_t clockid,899 struct posix_sigevent *restrict evp,900 posix_timer_t *restrict timerid)901 {902 // TODO903 not_implemented();904 }905 906 /**907 *908 * @param timerid909 * @return910 */911 int posix_timer_delete(posix_timer_t timerid)912 {913 // TODO914 not_implemented();915 }916 917 /**918 *919 * @param timerid920 * @return921 */922 int posix_timer_getoverrun(posix_timer_t timerid)923 {924 // TODO925 not_implemented();926 }927 928 /**929 *930 * @param timerid931 * @param value932 * @return933 */934 int posix_timer_gettime(posix_timer_t timerid,935 struct posix_itimerspec *value)936 {937 // TODO938 not_implemented();939 }940 941 /**942 *943 * @param timerid944 * @param flags945 * @param value946 * @param ovalue947 * @return948 */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 // TODO954 not_implemented();955 }956 957 #endif958 959 885 /** 960 886 * Get CPU time used since the process invocation.
Note:
See TracChangeset
for help on using the changeset viewer.