time.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Utility routines.
  4. *
  5. * Copyright (C) 2007 Denys Vlasenko
  6. *
  7. * Licensed under GPL version 2, see file LICENSE in this tarball for details.
  8. */
  9. #include "libbb.h"
  10. void FAST_FUNC parse_datestr(const char *date_str, struct tm *tm_time)
  11. {
  12. char end = '\0';
  13. const char *last_colon = strrchr(date_str, ':');
  14. if (last_colon != NULL) {
  15. /* Parse input and assign appropriately to tm_time */
  16. /* HH:MM */
  17. if (sscanf(date_str, "%u:%u%c",
  18. &tm_time->tm_hour,
  19. &tm_time->tm_min,
  20. &end) >= 2) {
  21. /* no adjustments needed */
  22. } else
  23. /* mm.dd-HH:MM */
  24. if (sscanf(date_str, "%u.%u-%u:%u%c",
  25. &tm_time->tm_mon, &tm_time->tm_mday,
  26. &tm_time->tm_hour, &tm_time->tm_min,
  27. &end) >= 4) {
  28. /* Adjust month from 1-12 to 0-11 */
  29. tm_time->tm_mon -= 1;
  30. } else
  31. /* yyyy.mm.dd-HH:MM */
  32. if (sscanf(date_str, "%u.%u.%u-%u:%u%c", &tm_time->tm_year,
  33. &tm_time->tm_mon, &tm_time->tm_mday,
  34. &tm_time->tm_hour, &tm_time->tm_min,
  35. &end) >= 5) {
  36. tm_time->tm_year -= 1900; /* Adjust years */
  37. tm_time->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */
  38. } else
  39. /* yyyy-mm-dd HH:MM */
  40. if (sscanf(date_str, "%u-%u-%u %u:%u%c", &tm_time->tm_year,
  41. &tm_time->tm_mon, &tm_time->tm_mday,
  42. &tm_time->tm_hour, &tm_time->tm_min,
  43. &end) >= 5) {
  44. tm_time->tm_year -= 1900; /* Adjust years */
  45. tm_time->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */
  46. //TODO: coreutils 6.9 also accepts "yyyy-mm-dd HH" (no minutes)
  47. } else {
  48. bb_error_msg_and_die(bb_msg_invalid_date, date_str);
  49. }
  50. if (end == ':') {
  51. /* xxx:SS */
  52. if (sscanf(last_colon + 1, "%u%c", &tm_time->tm_sec, &end) == 1)
  53. end = '\0';
  54. /* else end != NUL and we error out */
  55. }
  56. } else {
  57. /* Googled the following on an old date manpage:
  58. *
  59. * The canonical representation for setting the date/time is:
  60. * cc Century (either 19 or 20)
  61. * yy Year in abbreviated form (e.g. 89, 06)
  62. * mm Numeric month, a number from 1 to 12
  63. * dd Day, a number from 1 to 31
  64. * HH Hour, a number from 0 to 23
  65. * MM Minutes, a number from 0 to 59
  66. * ss Seconds, a number from 0 to 61 (with leap seconds)
  67. * Everything but the minutes is optional
  68. *
  69. * This coincides with the format of "touch -t TIME"
  70. */
  71. int len = strchrnul(date_str, '.') - date_str;
  72. /* MM[.SS] */
  73. if (len == 2 && sscanf(date_str, "%2u%2u%2u%2u%2u%c" + 12,
  74. &tm_time->tm_min,
  75. &end) >= 1) {
  76. } else
  77. /* HHMM[.SS] */
  78. if (len == 4 && sscanf(date_str, "%2u%2u%2u%2u%2u%c" + 9,
  79. &tm_time->tm_hour,
  80. &tm_time->tm_min,
  81. &end) >= 2) {
  82. } else
  83. /* ddHHMM[.SS] */
  84. if (len == 6 && sscanf(date_str, "%2u%2u%2u%2u%2u%c" + 6,
  85. &tm_time->tm_mday,
  86. &tm_time->tm_hour,
  87. &tm_time->tm_min,
  88. &end) >= 3) {
  89. } else
  90. /* mmddHHMM[.SS] */
  91. if (len == 8 && sscanf(date_str, "%2u%2u%2u%2u%2u%c" + 3,
  92. &tm_time->tm_mon,
  93. &tm_time->tm_mday,
  94. &tm_time->tm_hour,
  95. &tm_time->tm_min,
  96. &end) >= 4) {
  97. /* Adjust month from 1-12 to 0-11 */
  98. tm_time->tm_mon -= 1;
  99. } else
  100. /* yymmddHHMM[.SS] */
  101. if (len == 10 && sscanf(date_str, "%2u%2u%2u%2u%2u%c",
  102. &tm_time->tm_year,
  103. &tm_time->tm_mon,
  104. &tm_time->tm_mday,
  105. &tm_time->tm_hour,
  106. &tm_time->tm_min,
  107. &end) >= 5) {
  108. /* Adjust month from 1-12 to 0-11 */
  109. tm_time->tm_mon -= 1;
  110. } else
  111. /* yyyymmddHHMM[.SS] */
  112. if (len == 12 && sscanf(date_str, "%4u%2u%2u%2u%2u%c",
  113. &tm_time->tm_year,
  114. &tm_time->tm_mon,
  115. &tm_time->tm_mday,
  116. &tm_time->tm_hour,
  117. &tm_time->tm_min,
  118. &end) >= 5) {
  119. tm_time->tm_year -= 1900; /* Adjust years */
  120. tm_time->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */
  121. } else {
  122. bb_error_msg_and_die(bb_msg_invalid_date, date_str);
  123. }
  124. if (end == '.') {
  125. /* xxx.SS */
  126. if (sscanf(strchr(date_str, '.') + 1, "%u%c",
  127. &tm_time->tm_sec, &end) == 1)
  128. end = '\0';
  129. /* else end != NUL and we error out */
  130. }
  131. }
  132. if (end != '\0') {
  133. bb_error_msg_and_die(bb_msg_invalid_date, date_str);
  134. }
  135. }
  136. time_t FAST_FUNC validate_tm_time(const char *date_str, struct tm *tm_time)
  137. {
  138. time_t t = mktime(tm_time);
  139. if (t == (time_t) -1L) {
  140. bb_error_msg_and_die(bb_msg_invalid_date, date_str);
  141. }
  142. return t;
  143. }
  144. #if ENABLE_MONOTONIC_SYSCALL
  145. #include <sys/syscall.h>
  146. /* Old glibc (< 2.3.4) does not provide this constant. We use syscall
  147. * directly so this definition is safe. */
  148. #ifndef CLOCK_MONOTONIC
  149. #define CLOCK_MONOTONIC 1
  150. #endif
  151. /* libc has incredibly messy way of doing this,
  152. * typically requiring -lrt. We just skip all this mess */
  153. static void get_mono(struct timespec *ts)
  154. {
  155. if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, ts))
  156. bb_error_msg_and_die("clock_gettime(MONOTONIC) failed");
  157. }
  158. unsigned long long FAST_FUNC monotonic_ns(void)
  159. {
  160. struct timespec ts;
  161. get_mono(&ts);
  162. return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
  163. }
  164. unsigned long long FAST_FUNC monotonic_us(void)
  165. {
  166. struct timespec ts;
  167. get_mono(&ts);
  168. return ts.tv_sec * 1000000ULL + ts.tv_nsec/1000;
  169. }
  170. unsigned FAST_FUNC monotonic_sec(void)
  171. {
  172. struct timespec ts;
  173. get_mono(&ts);
  174. return ts.tv_sec;
  175. }
  176. #else
  177. unsigned long long FAST_FUNC monotonic_ns(void)
  178. {
  179. struct timeval tv;
  180. gettimeofday(&tv, NULL);
  181. return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000;
  182. }
  183. unsigned long long FAST_FUNC monotonic_us(void)
  184. {
  185. struct timeval tv;
  186. gettimeofday(&tv, NULL);
  187. return tv.tv_sec * 1000000ULL + tv.tv_usec;
  188. }
  189. unsigned FAST_FUNC monotonic_sec(void)
  190. {
  191. return time(NULL);
  192. }
  193. #endif