time.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2021, Sangoma Technologies Corporation
  5. *
  6. * See http://www.asterisk.org for more information about
  7. * the Asterisk project. Please do not directly contact
  8. * any of the maintainers of this project for assistance;
  9. * the project provides a web site, mailing lists and IRC
  10. * channels for your use.
  11. *
  12. * This program is free software, distributed under the terms of
  13. * the GNU General Public License Version 2. See the LICENSE file
  14. * at the top of the source tree.
  15. */
  16. /*! \file
  17. *
  18. * \brief Date/Time utility functions
  19. */
  20. /*** MODULEINFO
  21. <support_level>core</support_level>
  22. ***/
  23. #include <inttypes.h>
  24. #include <string.h>
  25. #include <strings.h>
  26. #include <time.h>
  27. #include "asterisk/time.h"
  28. const char *nanosecond_labels[] = {"ns", "nsec", "nanosecond"};
  29. const char *microsecond_labels[] = {"us", "usec", "microsecond"};
  30. const char *millisecond_labels[] = {"ms", "msec", "millisecond"};
  31. const char *second_labels[] = {"s", "sec", "second"};
  32. const char *minute_labels[] = {"m", "min", "minute"};
  33. const char *hour_labels[] = {"h", "hr", "hour"};
  34. const char *day_labels[] = {"d", "", "day"};
  35. const char *week_labels[] = {"w", "wk", "week"};
  36. const char *month_labels[] = {"mo", "mth", "month"};
  37. const char *year_labels[] = {"y", "yr", "year"};
  38. #define MAX_UNIT_LABELS 3
  39. struct time_unit_labels {
  40. enum TIME_UNIT unit;
  41. const char **values;
  42. };
  43. static struct time_unit_labels unit_labels[] = {
  44. { TIME_UNIT_NANOSECOND, nanosecond_labels },
  45. { TIME_UNIT_MICROSECOND, microsecond_labels },
  46. { TIME_UNIT_MILLISECOND, millisecond_labels },
  47. { TIME_UNIT_MONTH, month_labels }, /* Here so "mo" matches before "m" */
  48. { TIME_UNIT_SECOND, second_labels },
  49. { TIME_UNIT_MINUTE, minute_labels },
  50. { TIME_UNIT_HOUR, hour_labels },
  51. { TIME_UNIT_DAY, day_labels },
  52. { TIME_UNIT_WEEK, week_labels },
  53. { TIME_UNIT_YEAR, year_labels },
  54. };
  55. const unsigned int unit_labels_size = sizeof(unit_labels) / sizeof(0[unit_labels]);
  56. enum TIME_UNIT ast_time_str_to_unit(const char *unit)
  57. {
  58. size_t i, j;
  59. if (!unit) {
  60. return TIME_UNIT_ERROR;
  61. }
  62. for (i = 0; i < unit_labels_size; ++i) {
  63. for (j = 0; j < MAX_UNIT_LABELS; ++j) {
  64. /*
  65. * A lazy pluralization check. If the given unit string at least starts
  66. * with a label assume a match.
  67. */
  68. if (*unit_labels[i].values[j] && !strncasecmp(unit, unit_labels[i].values[j],
  69. strlen(unit_labels[i].values[j]))) {
  70. return unit_labels[i].unit;
  71. }
  72. }
  73. }
  74. return TIME_UNIT_ERROR;
  75. }
  76. ast_suseconds_t ast_time_tv_to_usec(const struct timeval *tv)
  77. {
  78. return tv->tv_sec * 1000000 + tv->tv_usec;
  79. }
  80. struct timeval ast_time_create(ast_time_t sec, ast_suseconds_t usec)
  81. {
  82. return ast_tv(sec, usec);
  83. }
  84. /*!
  85. * \brief Create a timeval first converting the given microsecond value
  86. * into seconds and microseconds
  87. *
  88. * \param usec microsecond value
  89. *
  90. * \return A timeval structure
  91. */
  92. static struct timeval normalize_and_create(unsigned long usec)
  93. {
  94. return ast_time_create(usec / 1000000, usec % 1000000);
  95. }
  96. struct timeval ast_time_create_by_unit(unsigned long val, enum TIME_UNIT unit)
  97. {
  98. switch (unit) {
  99. case TIME_UNIT_NANOSECOND:
  100. return normalize_and_create(val / 1000);
  101. case TIME_UNIT_MICROSECOND:
  102. return normalize_and_create(val);
  103. case TIME_UNIT_MILLISECOND:
  104. return normalize_and_create(val * 1000);
  105. case TIME_UNIT_SECOND:
  106. return ast_time_create(val, 0);
  107. case TIME_UNIT_MINUTE:
  108. return ast_time_create(val * 60, 0);
  109. case TIME_UNIT_HOUR:
  110. return ast_time_create(val * 3600, 0);
  111. case TIME_UNIT_DAY:
  112. return ast_time_create(val * 86400, 0);
  113. case TIME_UNIT_WEEK:
  114. return ast_time_create(val * 604800, 0);
  115. case TIME_UNIT_MONTH:
  116. /* Using Gregorian mean month - 30.436875 * 86400 */
  117. return ast_time_create(val * 2629746, 0);
  118. case TIME_UNIT_YEAR:
  119. /* Using Gregorian year - 365.2425 * 86400 */
  120. return ast_time_create(val * 31556952, 0);
  121. default:
  122. return ast_time_create(0, 0);
  123. }
  124. }
  125. struct timeval ast_time_create_by_unit_str(unsigned long val, const char *unit)
  126. {
  127. return ast_time_create_by_unit(val, ast_time_str_to_unit(unit));
  128. }
  129. /*!
  130. * \brief Returns a string representation of a time_t as decimal seconds
  131. * since the epoch.
  132. */
  133. int ast_time_t_to_string(time_t time, char *buf, size_t length)
  134. {
  135. struct tm tm;
  136. localtime_r(&time, &tm);
  137. return (strftime(buf, length, "%s", &tm) == 0) ? -1 : 0;
  138. }
  139. /*!
  140. * \brief Returns a time_t from a string containing seconds since the epoch.
  141. */
  142. time_t ast_string_to_time_t(const char *str)
  143. {
  144. struct tm tm = { 0, };
  145. /* handle leading spaces */
  146. if (strptime(str, " %s", &tm) == NULL) {
  147. return (time_t)-1;
  148. }
  149. tm.tm_isdst = -1;
  150. return mktime(&tm);
  151. }