Changes in uspace/lib/c/generic/time.c [3e6a98c5:f9b2cb4c] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/time.c
r3e6a98c5 rf9b2cb4c 54 54 #include <malloc.h> 55 55 56 #define ASCTIME_BUF_LEN 26 56 #define ASCTIME_BUF_LEN 26 57 58 #define HOURS_PER_DAY 24 59 #define MINS_PER_HOUR 60 60 #define SECS_PER_MIN 60 61 #define USECS_PER_SEC 1000000 62 #define MINS_PER_DAY (MINS_PER_HOUR * HOURS_PER_DAY) 63 #define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR) 64 #define SECS_PER_DAY (SECS_PER_HOUR * HOURS_PER_DAY) 57 65 58 66 /** Pointer to kernel shared variables with time */ … … 63 71 } *ktime = NULL; 64 72 65 /* Helper functions ***********************************************************/ 66 67 #define HOURS_PER_DAY (24) 68 #define MINS_PER_HOUR (60) 69 #define SECS_PER_MIN (60) 70 #define MINS_PER_DAY (MINS_PER_HOUR * HOURS_PER_DAY) 71 #define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR) 72 #define SECS_PER_DAY (SECS_PER_HOUR * HOURS_PER_DAY) 73 74 /** 75 * Checks whether the year is a leap year. 73 static async_sess_t *clock_conn = NULL; 74 75 /** Check whether the year is a leap year. 76 76 * 77 77 * @param year Year since 1900 (e.g. for 1970, the value is 70). 78 * 78 79 * @return true if year is a leap year, false otherwise 79 */ 80 static bool _is_leap_year(time_t year) 80 * 81 */ 82 static bool is_leap_year(time_t year) 81 83 { 82 84 year += 1900; 83 85 84 86 if (year % 400 == 0) 85 87 return true; 88 86 89 if (year % 100 == 0) 87 90 return false; 91 88 92 if (year % 4 == 0) 89 93 return true; 94 90 95 return false; 91 96 } 92 97 93 /** 94 * Returns how many days there are in the given month of the given year. 98 /** How many days there are in the given month 99 * 100 * Return how many days there are in the given month of the given year. 95 101 * Note that year is only taken into account if month is February. 96 102 * 97 103 * @param year Year since 1900 (can be negative). 98 * @param mon Month of the year. 0 for January, 11 for December. 104 * @param mon Month of the year. 0 for January, 11 for December. 105 * 99 106 * @return Number of days in the specified month. 100 */ 101 static int _days_in_month(time_t year, time_t mon) 102 { 103 assert(mon >= 0 && mon <= 11); 104 105 static int month_days[] = 106 { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 107 107 * 108 */ 109 static int days_in_month(time_t year, time_t mon) 110 { 111 assert(mon >= 0); 112 assert(mon <= 11); 113 114 static int month_days[] = { 115 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 116 }; 117 108 118 if (mon == 1) { 119 /* February */ 109 120 year += 1900; 110 /* february */111 return _is_leap_year(year) ? 29 : 28;112 } else {113 114 115 } 116 117 /**118 * For specified year, month and day of month, return swhich day of that year121 return is_leap_year(year) ? 29 : 28; 122 } 123 124 return month_days[mon]; 125 } 126 127 /** Which day of that year it is. 128 * 129 * For specified year, month and day of month, return which day of that year 119 130 * it is. 120 131 * 121 132 * For example, given date 2011-01-03, the corresponding expression is: 122 * _day_of_year(111, 0, 3) == 2133 * day_of_year(111, 0, 3) == 2 123 134 * 124 135 * @param year Year (year 1900 = 0, can be negative). 125 * @param mon Month (January = 0).136 * @param mon Month (January = 0). 126 137 * @param mday Day of month (First day is 1). 138 * 127 139 * @return Day of year (First day is 0). 128 */ 129 static int _day_of_year(time_t year, time_t mon, time_t mday) 130 { 131 static int mdays[] = 132 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; 133 static int leap_mdays[] = 134 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }; 135 136 return (_is_leap_year(year) ? leap_mdays[mon] : mdays[mon]) + mday - 1; 137 } 138 139 /** 140 * Integer division that rounds to negative infinity. 141 * Used by some functions in this file. 140 * 141 */ 142 static int day_of_year(time_t year, time_t mon, time_t mday) 143 { 144 static int mdays[] = { 145 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 146 }; 147 148 static int leap_mdays[] = { 149 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 150 }; 151 152 return (is_leap_year(year) ? leap_mdays[mon] : mdays[mon]) + mday - 1; 153 } 154 155 /** Integer division that rounds to negative infinity. 156 * 157 * Used by some functions in this module. 142 158 * 143 159 * @param op1 Dividend. 144 160 * @param op2 Divisor. 161 * 145 162 * @return Rounded quotient. 146 */ 147 static time_t _floor_div(time_t op1, time_t op2) 148 { 149 if (op1 >= 0 || op1 % op2 == 0) { 163 * 164 */ 165 static time_t floor_div(time_t op1, time_t op2) 166 { 167 if ((op1 >= 0) || (op1 % op2 == 0)) 150 168 return op1 / op2; 151 } else { 152 return op1 / op2 - 1; 153 } 154 } 155 156 /** 157 * Modulo that rounds to negative infinity. 158 * Used by some functions in this file. 169 170 return op1 / op2 - 1; 171 } 172 173 /** Modulo that rounds to negative infinity. 174 * 175 * Used by some functions in this module. 159 176 * 160 177 * @param op1 Dividend. 161 178 * @param op2 Divisor. 179 * 162 180 * @return Remainder. 163 */ 164 static time_t _floor_mod(time_t op1, time_t op2) 165 { 166 int div = _floor_div(op1, op2); 167 168 /* (a / b) * b + a % b == a */ 169 /* thus, a % b == a - (a / b) * b */ 170 171 int result = op1 - div * op2; 172 173 /* Some paranoid checking to ensure I didn't make a mistake here. */ 181 * 182 */ 183 static time_t floor_mod(time_t op1, time_t op2) 184 { 185 time_t div = floor_div(op1, op2); 186 187 /* 188 * (a / b) * b + a % b == a 189 * Thus: a % b == a - (a / b) * b 190 */ 191 192 time_t result = op1 - div * op2; 193 194 /* Some paranoid checking to ensure there is mistake here. */ 174 195 assert(result >= 0); 175 196 assert(result < op2); … … 179 200 } 180 201 181 /** 182 * Number of days since the Epoch.202 /** Number of days since the Epoch. 203 * 183 204 * Epoch is 1970-01-01, which is also equal to day 0. 184 205 * 185 206 * @param year Year (year 1900 = 0, may be negative). 186 * @param mon Month (January = 0).207 * @param mon Month (January = 0). 187 208 * @param mday Day of month (first day = 1). 209 * 188 210 * @return Number of days since the Epoch. 189 */ 190 static time_t _days_since_epoch(time_t year, time_t mon, time_t mday) 191 { 192 return (year - 70) * 365 + _floor_div(year - 69, 4) - 193 _floor_div(year - 1, 100) + _floor_div(year + 299, 400) + 194 _day_of_year(year, mon, mday); 195 } 196 197 /** 198 * Seconds since the Epoch. see also _days_since_epoch(). 199 * 211 * 212 */ 213 static time_t days_since_epoch(time_t year, time_t mon, time_t mday) 214 { 215 return (year - 70) * 365 + floor_div(year - 69, 4) - 216 floor_div(year - 1, 100) + floor_div(year + 299, 400) + 217 day_of_year(year, mon, mday); 218 } 219 220 /** Seconds since the Epoch. 221 * 222 * See also days_since_epoch(). 223 * 200 224 * @param tm Normalized broken-down time. 225 * 201 226 * @return Number of seconds since the epoch, not counting leap seconds. 202 */ 203 static time_t _secs_since_epoch(const struct tm *tm) 204 { 205 return _days_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday) * 227 * 228 */ 229 static time_t secs_since_epoch(const struct tm *tm) 230 { 231 return days_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday) * 206 232 SECS_PER_DAY + tm->tm_hour * SECS_PER_HOUR + 207 233 tm->tm_min * SECS_PER_MIN + tm->tm_sec; 208 234 } 209 235 210 /** 211 * Which day of week the specified date is. 212 * 236 /** Which day of week the specified date is. 237 * 213 238 * @param year Year (year 1900 = 0). 214 * @param mon Month (January = 0).239 * @param mon Month (January = 0). 215 240 * @param mday Day of month (first = 1). 241 * 216 242 * @return Day of week (Sunday = 0). 217 */ 218 static int _day_of_week(time_t year, time_t mon, time_t mday) 243 * 244 */ 245 static time_t day_of_week(time_t year, time_t mon, time_t mday) 219 246 { 220 247 /* 1970-01-01 is Thursday */ 221 return _floor_mod((_days_since_epoch(year, mon, mday) + 4), 7);222 } 223 224 /** 225 * Normalizes the broken-down time and optionally adds specified amount of226 * seconds.227 * 248 return floor_mod(days_since_epoch(year, mon, mday) + 4, 7); 249 } 250 251 /** Normalize the broken-down time. 252 * 253 * Optionally add specified amount of seconds. 254 * 228 255 * @param tm Broken-down time to normalize. 229 * @param sec_add Seconds to add. 256 * @param tv Timeval to add. 257 * 230 258 * @return 0 on success, -1 on overflow 231 */ 232 static int _normalize_time(struct tm *tm, time_t sec_add) 259 * 260 */ 261 static int normalize_tm_tv(struct tm *tm, const struct timeval *tv) 233 262 { 234 263 // TODO: DST correction 235 264 236 265 /* Set initial values. */ 237 time_t sec = tm->tm_sec + sec_add; 266 time_t usec = tm->tm_usec + tv->tv_usec; 267 time_t sec = tm->tm_sec + tv->tv_sec; 238 268 time_t min = tm->tm_min; 239 269 time_t hour = tm->tm_hour; … … 241 271 time_t mon = tm->tm_mon; 242 272 time_t year = tm->tm_year; 243 273 244 274 /* Adjust time. */ 245 min += _floor_div(sec, SECS_PER_MIN); 246 sec = _floor_mod(sec, SECS_PER_MIN); 247 hour += _floor_div(min, MINS_PER_HOUR); 248 min = _floor_mod(min, MINS_PER_HOUR); 249 day += _floor_div(hour, HOURS_PER_DAY); 250 hour = _floor_mod(hour, HOURS_PER_DAY); 251 275 sec += floor_div(usec, USECS_PER_SEC); 276 usec = floor_mod(usec, USECS_PER_SEC); 277 min += floor_div(sec, SECS_PER_MIN); 278 sec = floor_mod(sec, SECS_PER_MIN); 279 hour += floor_div(min, MINS_PER_HOUR); 280 min = floor_mod(min, MINS_PER_HOUR); 281 day += floor_div(hour, HOURS_PER_DAY); 282 hour = floor_mod(hour, HOURS_PER_DAY); 283 252 284 /* Adjust month. */ 253 year += _floor_div(mon, 12);254 mon = _floor_mod(mon, 12);255 285 year += floor_div(mon, 12); 286 mon = floor_mod(mon, 12); 287 256 288 /* Now the difficult part - days of month. */ 257 289 258 290 /* First, deal with whole cycles of 400 years = 146097 days. */ 259 year += _floor_div(day, 146097) * 400;260 day = _floor_mod(day, 146097);291 year += floor_div(day, 146097) * 400; 292 day = floor_mod(day, 146097); 261 293 262 294 /* Then, go in one year steps. */ … … 264 296 /* January and February. */ 265 297 while (day > 365) { 266 day -= _is_leap_year(year) ? 366 : 365;298 day -= is_leap_year(year) ? 366 : 365; 267 299 year++; 268 300 } … … 270 302 /* Rest of the year. */ 271 303 while (day > 365) { 272 day -= _is_leap_year(year + 1) ? 366 : 365;304 day -= is_leap_year(year + 1) ? 366 : 365; 273 305 year++; 274 306 } … … 276 308 277 309 /* Finally, finish it off month per month. */ 278 while (day >= _days_in_month(year, mon)) {279 day -= _days_in_month(year, mon);310 while (day >= days_in_month(year, mon)) { 311 day -= days_in_month(year, mon); 280 312 mon++; 313 281 314 if (mon >= 12) { 282 315 mon -= 12; … … 286 319 287 320 /* Calculate the remaining two fields. */ 288 tm->tm_yday = _day_of_year(year, mon, day + 1);289 tm->tm_wday = _day_of_week(year, mon, day + 1);321 tm->tm_yday = day_of_year(year, mon, day + 1); 322 tm->tm_wday = day_of_week(year, mon, day + 1); 290 323 291 324 /* And put the values back to the struct. */ 325 tm->tm_usec = (int) usec; 292 326 tm->tm_sec = (int) sec; 293 327 tm->tm_min = (int) min; … … 296 330 tm->tm_mon = (int) mon; 297 331 298 /* Casts to work around libcbrain-damage. */299 if (year > ((int) INT_MAX) || year < ((int)INT_MIN)) {300 tm->tm_year = (year < 0) ? ((int) INT_MIN) : ((int)INT_MAX);332 /* Casts to work around POSIX brain-damage. */ 333 if (year > ((int) INT_MAX) || year < ((int) INT_MIN)) { 334 tm->tm_year = (year < 0) ? ((int) INT_MIN) : ((int) INT_MAX); 301 335 return -1; 302 336 } … … 306 340 } 307 341 308 /** 309 * Which day the week-based year starts on, relative to the first calendar day. 310 * E.g. if the year starts on December 31st, the return value is -1. 342 static int normalize_tm_time(struct tm *tm, time_t time) 343 { 344 struct timeval tv = { 345 .tv_sec = time, 346 .tv_usec = 0 347 }; 348 349 return normalize_tm_tv(tm, &tv); 350 } 351 352 353 /** Which day the week-based year starts on. 354 * 355 * Relative to the first calendar day. E.g. if the year starts 356 * on December 31st, the return value is -1. 311 357 * 312 358 * @param Year since 1900. 359 * 313 360 * @return Offset of week-based year relative to calendar year. 314 */ 315 static int _wbyear_offset(int year) 316 { 317 int start_wday = _day_of_week(year, 0, 1); 318 return _floor_mod(4 - start_wday, 7) - 3; 319 } 320 321 /** 322 * Returns week-based year of the specified time. 361 * 362 */ 363 static int wbyear_offset(int year) 364 { 365 int start_wday = day_of_week(year, 0, 1); 366 367 return floor_mod(4 - start_wday, 7) - 3; 368 } 369 370 /** Week-based year of the specified time. 323 371 * 324 372 * @param tm Normalized broken-down time. 373 * 325 374 * @return Week-based year. 326 */ 327 static int _wbyear(const struct tm *tm) 328 { 329 int day = tm->tm_yday - _wbyear_offset(tm->tm_year); 375 * 376 */ 377 static int wbyear(const struct tm *tm) 378 { 379 int day = tm->tm_yday - wbyear_offset(tm->tm_year); 380 330 381 if (day < 0) { 331 382 /* Last week of previous year. */ 332 383 return tm->tm_year - 1; 333 384 } 334 if (day > 364 + _is_leap_year(tm->tm_year)) { 385 386 if (day > 364 + is_leap_year(tm->tm_year)) { 335 387 /* First week of next year. */ 336 388 return tm->tm_year + 1; 337 389 } 390 338 391 /* All the other days are in the calendar year. */ 339 392 return tm->tm_year; 340 393 } 341 394 342 /** 343 * Week number of the year, assuming weeks start on sunday.395 /** Week number of the year (assuming weeks start on Sunday). 396 * 344 397 * The first Sunday of January is the first day of week 1; 345 398 * days in the new year before this are in week 0. 346 399 * 347 400 * @param tm Normalized broken-down time. 401 * 348 402 * @return The week number (0 - 53). 349 */ 350 static int _sun_week_number(const struct tm *tm) 351 { 352 int first_day = (7 - _day_of_week(tm->tm_year, 0, 1)) % 7; 403 * 404 */ 405 static int sun_week_number(const struct tm *tm) 406 { 407 int first_day = (7 - day_of_week(tm->tm_year, 0, 1)) % 7; 408 353 409 return (tm->tm_yday - first_day + 7) / 7; 354 410 } 355 411 356 /** 357 * Week number of the year, assuming weeks start on monday. 358 * If the week containing January 1st has four or more days in the new year, 359 * then it is considered week 1. Otherwise, it is the last week of the previous 360 * year, and the next week is week 1. Both January 4th and the first Thursday 412 /** Week number of the year (assuming weeks start on Monday). 413 * 414 * If the week containing January 1st has four or more days 415 * in the new year, then it is considered week 1. Otherwise, 416 * it is the last week of the previous year, and the next week 417 * is week 1. Both January 4th and the first Thursday 361 418 * of January are always in week 1. 362 419 * 363 420 * @param tm Normalized broken-down time. 421 * 364 422 * @return The week number (1 - 53). 365 */ 366 static int _iso_week_number(const struct tm *tm) 367 { 368 int day = tm->tm_yday - _wbyear_offset(tm->tm_year); 423 * 424 */ 425 static int iso_week_number(const struct tm *tm) 426 { 427 int day = tm->tm_yday - wbyear_offset(tm->tm_year); 428 369 429 if (day < 0) { 370 430 /* Last week of previous year. */ 371 431 return 53; 372 432 } 373 if (day > 364 + _is_leap_year(tm->tm_year)) { 433 434 if (day > 364 + is_leap_year(tm->tm_year)) { 374 435 /* First week of next year. */ 375 436 return 1; 376 437 } 438 377 439 /* All the other days give correct answer. */ 378 440 return (day / 7 + 1); 379 441 } 380 442 381 /** 382 * Week number of the year, assuming weeks start on monday.443 /** Week number of the year (assuming weeks start on Monday). 444 * 383 445 * The first Monday of January is the first day of week 1; 384 * days in the new year before this are in week 0. 446 * days in the new year before this are in week 0. 385 447 * 386 448 * @param tm Normalized broken-down time. 449 * 387 450 * @return The week number (0 - 53). 388 */ 389 static int _mon_week_number(const struct tm *tm) 390 { 391 int first_day = (1 - _day_of_week(tm->tm_year, 0, 1)) % 7; 451 * 452 */ 453 static int mon_week_number(const struct tm *tm) 454 { 455 int first_day = (1 - day_of_week(tm->tm_year, 0, 1)) % 7; 456 392 457 return (tm->tm_yday - first_day + 7) / 7; 393 458 } 394 459 395 /******************************************************************************/ 396 460 static void tv_normalize(struct timeval *tv) 461 { 462 while (tv->tv_usec > USECS_PER_SEC) { 463 tv->tv_sec++; 464 tv->tv_usec -= USECS_PER_SEC; 465 } 466 while (tv->tv_usec < 0) { 467 tv->tv_sec--; 468 tv->tv_usec += USECS_PER_SEC; 469 } 470 } 397 471 398 472 /** Add microseconds to given timeval. … … 402 476 * 403 477 */ 404 void tv_add(struct timeval *tv, suseconds_t usecs) 405 { 406 tv->tv_sec += usecs / 1000000; 407 tv->tv_usec += usecs % 1000000; 408 409 if (tv->tv_usec > 1000000) { 410 tv->tv_sec++; 411 tv->tv_usec -= 1000000; 412 } 413 } 414 415 /** Subtract two timevals. 478 void tv_add_diff(struct timeval *tv, suseconds_t usecs) 479 { 480 tv->tv_sec += usecs / USECS_PER_SEC; 481 tv->tv_usec += usecs % USECS_PER_SEC; 482 tv_normalize(tv); 483 } 484 485 /** Add two timevals. 416 486 * 417 487 * @param tv1 First timeval. 418 488 * @param tv2 Second timeval. 489 */ 490 void tv_add(struct timeval *tv1, struct timeval *tv2) 491 { 492 tv1->tv_sec += tv2->tv_sec; 493 tv1->tv_usec += tv2->tv_usec; 494 tv_normalize(tv1); 495 } 496 497 /** Subtract two timevals. 498 * 499 * @param tv1 First timeval. 500 * @param tv2 Second timeval. 419 501 * 420 502 * @return Difference between tv1 and tv2 (tv1 - tv2) in … … 422 504 * 423 505 */ 424 suseconds_t tv_sub (struct timeval *tv1, struct timeval *tv2)506 suseconds_t tv_sub_diff(struct timeval *tv1, struct timeval *tv2) 425 507 { 426 508 return (tv1->tv_usec - tv2->tv_usec) + 427 ((tv1->tv_sec - tv2->tv_sec) * 1000000); 509 ((tv1->tv_sec - tv2->tv_sec) * USECS_PER_SEC); 510 } 511 512 /** Subtract two timevals. 513 * 514 * @param tv1 First timeval. 515 * @param tv2 Second timeval. 516 * 517 */ 518 void tv_sub(struct timeval *tv1, struct timeval *tv2) 519 { 520 tv1->tv_sec -= tv2->tv_sec; 521 tv1->tv_usec -= tv2->tv_usec; 522 tv_normalize(tv1); 428 523 } 429 524 … … 468 563 } 469 564 470 /** Get time of day 565 /** Get time of day. 471 566 * 472 567 * The time variables are memory mapped (read-only) from kernel which … … 482 577 * 483 578 */ 484 int gettimeofday(struct timeval *tv, struct timezone *tz) 485 { 486 int rc; 487 struct tm t; 488 category_id_t cat_id; 489 size_t svc_cnt; 490 service_id_t *svc_ids = NULL; 491 service_id_t svc_id; 492 char *svc_name = NULL; 493 494 static async_sess_t *clock_conn = NULL; 495 579 void gettimeofday(struct timeval *tv, struct timezone *tz) 580 { 496 581 if (tz) { 497 582 tz->tz_minuteswest = 0; 498 583 tz->tz_dsttime = DST_NONE; 499 584 } 500 585 501 586 if (clock_conn == NULL) { 502 rc = loc_category_get_id("clock", &cat_id, IPC_FLAG_BLOCKING); 587 category_id_t cat_id; 588 int rc = loc_category_get_id("clock", &cat_id, IPC_FLAG_BLOCKING); 503 589 if (rc != EOK) 504 goto ret_uptime; 505 590 goto fallback; 591 592 service_id_t *svc_ids; 593 size_t svc_cnt; 506 594 rc = loc_category_get_svcs(cat_id, &svc_ids, &svc_cnt); 507 595 if (rc != EOK) 508 goto ret_uptime;509 596 goto fallback; 597 510 598 if (svc_cnt == 0) 511 goto ret_uptime; 512 599 goto fallback; 600 601 char *svc_name; 513 602 rc = loc_service_get_name(svc_ids[0], &svc_name); 603 free(svc_ids); 514 604 if (rc != EOK) 515 goto ret_uptime; 516 605 goto fallback; 606 607 service_id_t svc_id; 517 608 rc = loc_service_get_id(svc_name, &svc_id, 0); 609 free(svc_name); 518 610 if (rc != EOK) 519 goto ret_uptime;520 521 clock_conn = loc_service_connect( EXCHANGE_SERIALIZE,522 svc_id,IPC_FLAG_BLOCKING);611 goto fallback; 612 613 clock_conn = loc_service_connect(svc_id, INTERFACE_DDF, 614 IPC_FLAG_BLOCKING); 523 615 if (!clock_conn) 524 goto ret_uptime; 525 } 526 527 rc = clock_dev_time_get(clock_conn, &t); 616 goto fallback; 617 } 618 619 struct tm time; 620 int rc = clock_dev_time_get(clock_conn, &time); 528 621 if (rc != EOK) 529 goto ret_uptime; 530 531 tv->tv_usec = 0; 532 tv->tv_sec = mktime(&t); 533 534 free(svc_name); 535 free(svc_ids); 536 537 return EOK; 538 539 ret_uptime: 540 541 free(svc_name); 542 free(svc_ids); 543 544 return getuptime(tv); 545 } 546 547 int getuptime(struct timeval *tv) 622 goto fallback; 623 624 tv->tv_usec = time.tm_usec; 625 tv->tv_sec = mktime(&time); 626 627 return; 628 629 fallback: 630 getuptime(tv); 631 } 632 633 void getuptime(struct timeval *tv) 548 634 { 549 635 if (ktime == NULL) { … … 552 638 if (rc != EOK) { 553 639 errno = rc; 554 return -1;640 goto fallback; 555 641 } 556 642 557 void *addr ;558 rc = physmem_map( (void *) faddr, 1,559 AS_AREA_READ | AS_AREA_CACHEABLE,&addr);643 void *addr = AS_AREA_ANY; 644 rc = physmem_map(faddr, 1, AS_AREA_READ | AS_AREA_CACHEABLE, 645 &addr); 560 646 if (rc != EOK) { 561 647 as_area_destroy(addr); 562 648 errno = rc; 563 return -1;649 goto fallback; 564 650 } 565 651 … … 580 666 } else 581 667 tv->tv_sec = s1; 582 583 return 0; 668 669 return; 670 671 fallback: 672 tv->tv_sec = 0; 673 tv->tv_usec = 0; 584 674 } 585 675 … … 587 677 { 588 678 struct timeval tv; 589 if (gettimeofday(&tv, NULL)) 590 return (time_t) -1; 679 gettimeofday(&tv, NULL); 591 680 592 681 if (tloc) … … 631 720 } 632 721 633 /** 634 * This function first normalizes the provided broken-down time 635 * (moves all values to their proper bounds) and then tries to 636 * calculate the appropriate time_t representation. 722 /** Get time from broken-down time. 723 * 724 * First normalize the provided broken-down time 725 * (moves all values to their proper bounds) and 726 * then try to calculate the appropriate time_t 727 * representation. 637 728 * 638 729 * @param tm Broken-down time. 639 * @return time_t representation of the time, undefined value on overflow. 730 * 731 * @return time_t representation of the time. 732 * @return Undefined value on overflow. 733 * 640 734 */ 641 735 time_t mktime(struct tm *tm) … … 643 737 // TODO: take DST flag into account 644 738 // TODO: detect overflow 645 646 _normalize_time(tm, 0); 647 return _secs_since_epoch(tm); 648 } 649 650 /** 651 * Convert time and date to a string, based on a specified format and 652 * current locale. 653 * 654 * @param s Buffer to write string to. 739 740 normalize_tm_time(tm, 0); 741 return secs_since_epoch(tm); 742 } 743 744 /* 745 * FIXME: This requires POSIX-correct snprintf. 746 * Otherwise it won't work with non-ASCII chars. 747 */ 748 #define APPEND(...) \ 749 { \ 750 consumed = snprintf(ptr, remaining, __VA_ARGS__); \ 751 if (consumed >= remaining) \ 752 return 0; \ 753 \ 754 ptr += consumed; \ 755 remaining -= consumed; \ 756 } 757 758 #define RECURSE(fmt) \ 759 { \ 760 consumed = strftime(ptr, remaining, fmt, tm); \ 761 if (consumed == 0) \ 762 return 0; \ 763 \ 764 ptr += consumed; \ 765 remaining -= consumed; \ 766 } 767 768 #define TO_12H(hour) \ 769 (((hour) > 12) ? ((hour) - 12) : \ 770 (((hour) == 0) ? 12 : (hour))) 771 772 /** Convert time and date to a string. 773 * 774 * @param s Buffer to write string to. 655 775 * @param maxsize Size of the buffer. 656 * @param format Format of the output. 657 * @param tm Broken-down time to format. 776 * @param format Format of the output. 777 * @param tm Broken-down time to format. 778 * 658 779 * @return Number of bytes written. 780 * 659 781 */ 660 782 size_t strftime(char *restrict s, size_t maxsize, … … 664 786 assert(format != NULL); 665 787 assert(tm != NULL); 666 788 667 789 // TODO: use locale 790 668 791 static const char *wday_abbr[] = { 669 792 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 670 793 }; 794 671 795 static const char *wday[] = { 672 796 "Sunday", "Monday", "Tuesday", "Wednesday", 673 797 "Thursday", "Friday", "Saturday" 674 798 }; 799 675 800 static const char *mon_abbr[] = { 676 801 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 677 802 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 678 803 }; 804 679 805 static const char *mon[] = { 680 806 "January", "February", "March", "April", "May", "June", "July", … … 682 808 }; 683 809 684 if (maxsize < 1) {810 if (maxsize < 1) 685 811 return 0; 686 }687 812 688 813 char *ptr = s; … … 690 815 size_t remaining = maxsize; 691 816 692 #define append(...) { \693 /* FIXME: this requires POSIX-correct snprintf */ \694 /* otherwise it won't work with non-ascii chars */ \695 consumed = snprintf(ptr, remaining, __VA_ARGS__); \696 if (consumed >= remaining) { \697 return 0; \698 } \699 ptr += consumed; \700 remaining -= consumed; \701 }702 703 #define recurse(fmt) { \704 consumed = strftime(ptr, remaining, fmt, tm); \705 if (consumed == 0) { \706 return 0; \707 } \708 ptr += consumed; \709 remaining -= consumed; \710 }711 712 #define TO_12H(hour) (((hour) > 12) ? ((hour) - 12) : \713 (((hour) == 0) ? 12 : (hour)))714 715 817 while (*format != '\0') { 716 818 if (*format != '%') { 717 append("%c", *format);819 APPEND("%c", *format); 718 820 format++; 719 821 continue; … … 721 823 722 824 format++; 723 if ( *format == '0' || *format == '+') {825 if ((*format == '0') || (*format == '+')) { 724 826 // TODO: padding 725 827 format++; 726 828 } 829 727 830 while (isdigit(*format)) { 728 831 // TODO: padding 729 832 format++; 730 833 } 731 if (*format == 'O' || *format == 'E') { 834 835 if ((*format == 'O') || (*format == 'E')) { 732 836 // TODO: locale's alternative format 733 837 format++; … … 736 840 switch (*format) { 737 841 case 'a': 738 append("%s", wday_abbr[tm->tm_wday]); break; 842 APPEND("%s", wday_abbr[tm->tm_wday]); 843 break; 739 844 case 'A': 740 append("%s", wday[tm->tm_wday]); break; 845 APPEND("%s", wday[tm->tm_wday]); 846 break; 741 847 case 'b': 742 append("%s", mon_abbr[tm->tm_mon]); break; 848 APPEND("%s", mon_abbr[tm->tm_mon]); 849 break; 743 850 case 'B': 744 append("%s", mon[tm->tm_mon]); break; 851 APPEND("%s", mon[tm->tm_mon]); 852 break; 745 853 case 'c': 746 854 // TODO: locale-specific datetime format 747 recurse("%Y-%m-%d %H:%M:%S"); break; 855 RECURSE("%Y-%m-%d %H:%M:%S"); 856 break; 748 857 case 'C': 749 append("%02d", (1900 + tm->tm_year) / 100); break; 858 APPEND("%02d", (1900 + tm->tm_year) / 100); 859 break; 750 860 case 'd': 751 append("%02d", tm->tm_mday); break; 861 APPEND("%02d", tm->tm_mday); 862 break; 752 863 case 'D': 753 recurse("%m/%d/%y"); break; 864 RECURSE("%m/%d/%y"); 865 break; 754 866 case 'e': 755 append("%2d", tm->tm_mday); break; 867 APPEND("%2d", tm->tm_mday); 868 break; 756 869 case 'F': 757 recurse("%+4Y-%m-%d"); break; 870 RECURSE("%+4Y-%m-%d"); 871 break; 758 872 case 'g': 759 append("%02d", _wbyear(tm) % 100); break; 873 APPEND("%02d", wbyear(tm) % 100); 874 break; 760 875 case 'G': 761 append("%d", _wbyear(tm)); break; 876 APPEND("%d", wbyear(tm)); 877 break; 762 878 case 'h': 763 recurse("%b"); break; 879 RECURSE("%b"); 880 break; 764 881 case 'H': 765 append("%02d", tm->tm_hour); break; 882 APPEND("%02d", tm->tm_hour); 883 break; 766 884 case 'I': 767 append("%02d", TO_12H(tm->tm_hour)); break; 885 APPEND("%02d", TO_12H(tm->tm_hour)); 886 break; 768 887 case 'j': 769 append("%03d", tm->tm_yday); break; 888 APPEND("%03d", tm->tm_yday); 889 break; 770 890 case 'k': 771 append("%2d", tm->tm_hour); break; 891 APPEND("%2d", tm->tm_hour); 892 break; 772 893 case 'l': 773 append("%2d", TO_12H(tm->tm_hour)); break; 894 APPEND("%2d", TO_12H(tm->tm_hour)); 895 break; 774 896 case 'm': 775 append("%02d", tm->tm_mon); break; 897 APPEND("%02d", tm->tm_mon); 898 break; 776 899 case 'M': 777 append("%02d", tm->tm_min); break; 900 APPEND("%02d", tm->tm_min); 901 break; 778 902 case 'n': 779 append("\n"); break; 903 APPEND("\n"); 904 break; 780 905 case 'p': 781 append("%s", tm->tm_hour < 12 ? "AM" : "PM"); break; 906 APPEND("%s", tm->tm_hour < 12 ? "AM" : "PM"); 907 break; 782 908 case 'P': 783 append("%s", tm->tm_hour < 12 ? "am" : "PM"); break; 909 APPEND("%s", tm->tm_hour < 12 ? "am" : "PM"); 910 break; 784 911 case 'r': 785 recurse("%I:%M:%S %p"); break; 912 RECURSE("%I:%M:%S %p"); 913 break; 786 914 case 'R': 787 recurse("%H:%M"); break; 915 RECURSE("%H:%M"); 916 break; 788 917 case 's': 789 append("%ld", _secs_since_epoch(tm)); break; 918 APPEND("%ld", secs_since_epoch(tm)); 919 break; 790 920 case 'S': 791 append("%02d", tm->tm_sec); break; 921 APPEND("%02d", tm->tm_sec); 922 break; 792 923 case 't': 793 append("\t"); break; 924 APPEND("\t"); 925 break; 794 926 case 'T': 795 recurse("%H:%M:%S"); break; 927 RECURSE("%H:%M:%S"); 928 break; 796 929 case 'u': 797 append("%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);930 APPEND("%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday); 798 931 break; 799 932 case 'U': 800 append("%02d", _sun_week_number(tm)); break; 933 APPEND("%02d", sun_week_number(tm)); 934 break; 801 935 case 'V': 802 append("%02d", _iso_week_number(tm)); break; 936 APPEND("%02d", iso_week_number(tm)); 937 break; 803 938 case 'w': 804 append("%d", tm->tm_wday); break; 939 APPEND("%d", tm->tm_wday); 940 break; 805 941 case 'W': 806 append("%02d", _mon_week_number(tm)); break; 942 APPEND("%02d", mon_week_number(tm)); 943 break; 807 944 case 'x': 808 945 // TODO: locale-specific date format 809 recurse("%Y-%m-%d"); break; 946 RECURSE("%Y-%m-%d"); 947 break; 810 948 case 'X': 811 949 // TODO: locale-specific time format 812 recurse("%H:%M:%S"); break; 950 RECURSE("%H:%M:%S"); 951 break; 813 952 case 'y': 814 append("%02d", tm->tm_year % 100); break; 953 APPEND("%02d", tm->tm_year % 100); 954 break; 815 955 case 'Y': 816 append("%d", 1900 + tm->tm_year); break; 956 APPEND("%d", 1900 + tm->tm_year); 957 break; 817 958 case 'z': 818 959 // TODO: timezone … … 822 963 break; 823 964 case '%': 824 append("%%");965 APPEND("%%"); 825 966 break; 826 967 default: 827 968 /* Invalid specifier, print verbatim. */ 828 while (*format != '%') {969 while (*format != '%') 829 970 format--; 830 }831 append("%%");971 972 APPEND("%%"); 832 973 break; 833 974 } 975 834 976 format++; 835 977 } 836 978 837 #undef append838 #undef recurse839 840 979 return maxsize - remaining; 841 980 } 842 981 843 844 /** Converts a time value to a broken-down UTC time 845 * 846 * @param time Time to convert847 * @param result Structure to store the result to848 * 849 * @return EOK or a negative error code982 /** Convert a time value to a broken-down UTC time/ 983 * 984 * @param time Time to convert 985 * @param result Structure to store the result to 986 * 987 * @return EOK or a negative error code 988 * 850 989 */ 851 990 int time_utc2tm(const time_t time, struct tm *restrict result) 852 991 { 853 992 assert(result != NULL); 854 993 855 994 /* Set result to epoch. */ 995 result->tm_usec = 0; 856 996 result->tm_sec = 0; 857 997 result->tm_min = 0; … … 860 1000 result->tm_mon = 0; 861 1001 result->tm_year = 70; /* 1970 */ 862 863 if ( _normalize_time(result, time) == -1)1002 1003 if (normalize_tm_time(result, time) == -1) 864 1004 return EOVERFLOW; 865 1005 866 1006 return EOK; 867 1007 } 868 1008 869 /** Converts a time value to a null terminated string of the form 870 * "Wed Jun 30 21:49:08 1993\n" expressed in UTC. 871 * 872 * @param time Time to convert. 873 * @param buf Buffer to store the string to, must be at least 874 * ASCTIME_BUF_LEN bytes long. 875 * 876 * @return EOK or a negative error code. 1009 /** Convert a time value to a NULL-terminated string. 1010 * 1011 * The format is "Wed Jun 30 21:49:08 1993\n" expressed in UTC. 1012 * 1013 * @param time Time to convert. 1014 * @param buf Buffer to store the string to, must be at least 1015 * ASCTIME_BUF_LEN bytes long. 1016 * 1017 * @return EOK or a negative error code. 1018 * 877 1019 */ 878 1020 int time_utc2str(const time_t time, char *restrict buf) 879 1021 { 880 struct tm t; 881 int r; 882 883 if ((r = time_utc2tm(time, &t)) != EOK) 884 return r; 885 886 time_tm2str(&t, buf); 1022 struct tm tm; 1023 int ret = time_utc2tm(time, &tm); 1024 if (ret != EOK) 1025 return ret; 1026 1027 time_tm2str(&tm, buf); 887 1028 return EOK; 888 1029 } 889 1030 890 891 /** 892 * Converts broken-down time to a string in format 893 * "Sun Jan 1 00:00:00 1970\n". (Obsolete) 1031 /** Convert broken-down time to a NULL-terminated string. 1032 * 1033 * The format is "Sun Jan 1 00:00:00 1970\n". (Obsolete) 894 1034 * 895 1035 * @param timeptr Broken-down time structure. 896 * @param buf Buffer to store string to, must be at least ASCTIME_BUF_LEN 897 * bytes long. 1036 * @param buf Buffer to store string to, must be at least 1037 * ASCTIME_BUF_LEN bytes long. 1038 * 898 1039 */ 899 1040 void time_tm2str(const struct tm *restrict timeptr, char *restrict buf) … … 901 1042 assert(timeptr != NULL); 902 1043 assert(buf != NULL); 903 1044 904 1045 static const char *wday[] = { 905 1046 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 906 1047 }; 1048 907 1049 static const char *mon[] = { 908 1050 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 909 1051 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 910 1052 }; 911 1053 912 1054 snprintf(buf, ASCTIME_BUF_LEN, "%s %s %2d %02d:%02d:%02d %d\n", 913 1055 wday[timeptr->tm_wday], … … 918 1060 } 919 1061 920 /** 921 * Converts a time value to a broken-down local time, expressed relative 922 * to the user's specified timezone. 923 * 924 * @param timer Time to convert. 925 * @param result Structure to store the result to. 926 * 927 * @return EOK on success or a negative error code. 928 */ 929 int time_local2tm(const time_t time, struct tm *restrict result) 930 { 931 // TODO: deal with timezone 932 // currently assumes system and all times are in GMT 933 1062 /** Converts a time value to a broken-down local time. 1063 * 1064 * Time is expressed relative to the user's specified timezone. 1065 * 1066 * @param tv Timeval to convert. 1067 * @param result Structure to store the result to. 1068 * 1069 * @return EOK on success or a negative error code. 1070 * 1071 */ 1072 int time_tv2tm(const struct timeval *tv, struct tm *restrict result) 1073 { 1074 // TODO: Deal with timezones. 1075 // Currently assumes system and all times are in UTC 1076 934 1077 /* Set result to epoch. */ 1078 result->tm_usec = 0; 935 1079 result->tm_sec = 0; 936 1080 result->tm_min = 0; … … 939 1083 result->tm_mon = 0; 940 1084 result->tm_year = 70; /* 1970 */ 941 942 if ( _normalize_time(result, time) == -1)1085 1086 if (normalize_tm_tv(result, tv) == -1) 943 1087 return EOVERFLOW; 944 1088 945 1089 return EOK; 946 1090 } 947 1091 948 /** 949 * Converts the calendar time to a null terminated string 950 * of the form "Wed Jun 30 21:49:08 1993\n" expressed relative to the 1092 /** Converts a time value to a broken-down local time. 1093 * 1094 * Time is expressed relative to the user's specified timezone. 1095 * 1096 * @param timer Time to convert. 1097 * @param result Structure to store the result to. 1098 * 1099 * @return EOK on success or a negative error code. 1100 * 1101 */ 1102 int time_local2tm(const time_t time, struct tm *restrict result) 1103 { 1104 struct timeval tv = { 1105 .tv_sec = time, 1106 .tv_usec = 0 1107 }; 1108 1109 return time_tv2tm(&tv, result); 1110 } 1111 1112 /** Convert the calendar time to a NULL-terminated string. 1113 * 1114 * The format is "Wed Jun 30 21:49:08 1993\n" expressed relative to the 951 1115 * user's specified timezone. 952 * 953 * @param timer Time to convert. 954 * @param buf Buffer to store the string to. Must be at least 955 * ASCTIME_BUF_LEN bytes long. 956 * 957 * @return EOK on success or a negative error code. 1116 * 1117 * @param timer Time to convert. 1118 * @param buf Buffer to store the string to. Must be at least 1119 * ASCTIME_BUF_LEN bytes long. 1120 * 1121 * @return EOK on success or a negative error code. 1122 * 958 1123 */ 959 1124 int time_local2str(const time_t time, char *buf) 960 1125 { 961 1126 struct tm loctime; 962 int r; 963 964 if ((r = time_local2tm(time, &loctime)) != EOK) 965 return r; 966 1127 int ret = time_local2tm(time, &loctime); 1128 if (ret != EOK) 1129 return ret; 1130 967 1131 time_tm2str(&loctime, buf); 968 969 1132 return EOK; 970 1133 } 971 1134 972 /** 973 * Calculate the difference between two times, in seconds. 974 * 1135 /** Calculate the difference between two times, in seconds. 1136 * 975 1137 * @param time1 First time. 976 1138 * @param time0 Second time. 977 * @return Time in seconds. 1139 * 1140 * @return Time difference in seconds. 1141 * 978 1142 */ 979 1143 double difftime(time_t time1, time_t time0)
Note:
See TracChangeset
for help on using the changeset viewer.