LCOV - code coverage report
Current view: top level - src/utils - time-utils.c (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 75 79 94.9 %
Date: 2017-04-30 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Present - Date/Time Library
       3             :  *
       4             :  * Implementations of utility functions for dealing with dates and times
       5             :  *
       6             :  * Licensed under the MIT License.
       7             :  * For details, see LICENSE.
       8             :  */
       9             : 
      10             : #include <assert.h>
      11             : #include <math.h>
      12             : #include <stddef.h>
      13             : #include <string.h>
      14             : #include <time.h>
      15             : #include <unistd.h>
      16             : 
      17             : #include "present-config.h"
      18             : 
      19             : #ifdef PRESENT_WRAP_STDLIB_CALLS
      20             : # include <pthread.h>
      21             : #endif
      22             : 
      23             : #include "utils/constants.h"
      24             : #include "utils/impl-utils.h"
      25             : 
      26             : #include "utils/time-utils.h"
      27             : 
      28             : #ifdef PRESENT_WRAP_STDLIB_CALLS
      29             : static pthread_mutex_t stdlib_call_access;
      30             : static int is_initialized = 0;
      31             : 
      32             : #define INITIALIZE()                                        \
      33             :     do {                                                    \
      34             :         if (!is_initialized) {                              \
      35             :             pthread_mutex_init(&stdlib_call_access, NULL);  \
      36             :             is_initialized = 1;                             \
      37             :         }                                                   \
      38             :         pthread_mutex_lock(&stdlib_call_access);            \
      39             :     } while (0)
      40             : 
      41             : #define DONE()                                      \
      42             :     do {                                            \
      43             :         pthread_mutex_unlock(&stdlib_call_access);  \
      44             :     } while (0)
      45             : 
      46             : #else
      47             : 
      48             : #define INITIALIZE()
      49             : #define DONE()
      50             : 
      51             : #endif
      52             : 
      53             : static int is_test_time_set = 0;
      54             : static struct PresentNowStruct test_time;
      55             : 
      56             : /**
      57             :  * Calculate the number of days that have occurred since the very beginning
      58             :  * (January 1st) of a base year.
      59             :  *
      60             :  * Precondition: The base year MUST be divisible by 400.
      61             :  */
      62             : static int_timestamp
      63       10272 : days_since_base_year(
      64             :         const int_year base_year,
      65             :         int_year year,
      66             :         int_month month,
      67             :         int_day day)
      68             : {
      69             :     /** Day of the year that each month starts on (in non-leap years). */
      70             :     static const int_day_of_year DAY_OF_START_OF_MONTH[13] = {
      71             :         0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
      72             :     };
      73             : 
      74             :     int_timestamp offset_year;
      75             :     int_timestamp days_since_base;
      76             : 
      77             :     /* Fix irregularities in the month
      78             :        (we don't really care about irregularities in the day, since our final
      79             :        result is a number of days) */
      80       20567 :     while (month <= 0) {
      81          23 :         month += 12;
      82          23 :         year -= 1;
      83             :     }
      84       10272 :     if (month > 12) {
      85          10 :         year += (month - 1) / 12;
      86          10 :         month = (month - 1) % 12 + 1;
      87             :     }
      88             : 
      89       10272 :     offset_year = year - base_year;
      90             : 
      91             :     /* Start conversion to number of days since base */
      92       10272 :     days_since_base = day - 1;
      93             : 
      94       10272 :     days_since_base += DAY_OF_START_OF_MONTH[month];
      95       10272 :     days_since_base += 365 * offset_year;
      96             : 
      97             :     /* Every 4 years is a leap year */
      98       10272 :     days_since_base += offset_year / 4;
      99             :     /* Except the turn of the century */
     100       10272 :     days_since_base -= offset_year / 100;
     101             :     /* Except every 4th century */
     102       10272 :     days_since_base += offset_year / 400;
     103             : 
     104             :     /* If it's still January or February of this year, though, we don't need
     105             :        to include the extra for this year yet */
     106       10272 :     if (IS_LEAP_YEAR(year) && month <= 2) {
     107         631 :         days_since_base--;
     108             :     }
     109             : 
     110             :     /* This fix (i.e. hack) ensures compatibility with timegm behavior */
     111       10272 :     if (offset_year < 0 && !IS_LEAP_YEAR(year)) {
     112         608 :         days_since_base--;
     113             :     }
     114             : 
     115       10272 :     return days_since_base;
     116             : }
     117             : 
     118             : double
     119          10 : present_round(double x)
     120             : {
     121             :     double t;
     122             : 
     123          10 :     if (x >= 0.0) {
     124          10 :         t = floor(x);
     125          10 :         if (x - t >= 0.5) {
     126           2 :             t += 1.0;
     127             :         }
     128          10 :         return t;
     129             :     } else {
     130           0 :         t = floor(-x);
     131           0 :         if ((-x) - t >= 0.5) {
     132           0 :             t += 1.0;
     133             :         }
     134           0 :         return -t;
     135             :     }
     136             : }
     137             : 
     138             : /** Convert a time_t to a UNIX timestamp. */
     139             : int_timestamp
     140          33 : time_t_to_unix_timestamp(const time_t timestamp)
     141             : {
     142             :     /* TODO: We're just assuming that time_t is already a UNIX timestamp */
     143          33 :     return (int_timestamp) timestamp;
     144             : }
     145             : 
     146             : /** Convert a UNIX timestamp to a time_t. */
     147             : time_t
     148        5248 : unix_timestamp_to_time_t(const int_timestamp timestamp_seconds)
     149             : {
     150             :     /* TODO: We're just assuming that time_t is a UNIX timestamp */
     151        5248 :     return (time_t) timestamp_seconds;
     152             : }
     153             : 
     154             : int_timestamp
     155        5136 : to_unix_timestamp(
     156             :         int_year year,
     157             :         int_month month,
     158             :         int_day day,
     159             :         int_hour hour,
     160             :         int_minute minute,
     161             :         int_second second)
     162             : {
     163             :     /* 1600 is the easiest base year that's divisible by 400 */
     164             :     static const int_year BASE_YEAR = 1600;
     165        5136 :     const int_timestamp EPOCH_DAYS_SINCE_BASE_YEAR =
     166        5136 :         days_since_base_year(
     167             :                 BASE_YEAR,
     168             :                 UNIX_EPOCH_YEAR,
     169             :                 UNIX_EPOCH_MONTH,
     170             :                 UNIX_EPOCH_DAY);
     171             : 
     172             :     int_timestamp days_since_epoch;
     173             :     
     174        5136 :     days_since_epoch = days_since_base_year(BASE_YEAR, year, month, day) -
     175             :         EPOCH_DAYS_SINCE_BASE_YEAR;
     176             : 
     177       10272 :     return days_since_epoch * SECONDS_IN_DAY
     178        5136 :         + hour * SECONDS_IN_HOUR
     179        5136 :         + minute * SECONDS_IN_MINUTE
     180             :         + second;
     181             : }
     182             : 
     183             : void
     184        5235 : time_t_to_struct_tm(const time_t * timep, struct tm * result)
     185             : {
     186             :     struct tm * value;
     187             : 
     188             :     INITIALIZE();
     189        5235 :     value = gmtime(timep);
     190        5235 :     assert(value != NULL);
     191        5235 :     memcpy(result, value, sizeof(struct tm));
     192             :     DONE();
     193        5235 : }
     194             : 
     195             : time_t
     196           2 : struct_tm_to_time_t_local(struct tm * tm)
     197             : {
     198             :     time_t value;
     199             : 
     200             :     INITIALIZE();
     201           2 :     value = mktime(tm);
     202           2 :     assert(value != (time_t) -1);
     203             :     DONE();
     204           2 :     return value;
     205             : }
     206             : 
     207             : void
     208           6 : time_t_to_struct_tm_local(const time_t * timep, struct tm * result)
     209             : {
     210             :     struct tm * value;
     211             : 
     212             :     INITIALIZE();
     213           6 :     value = localtime(timep);
     214           6 :     assert(value != NULL);
     215           6 :     memcpy(result, value, sizeof(struct tm));
     216             :     DONE();
     217           6 : }
     218             : 
     219             : void
     220          20 : clean_struct_tm(struct tm * const tm)
     221             : {
     222             :     time_t time;
     223             : 
     224         120 :     time = unix_timestamp_to_time_t(to_unix_timestamp(
     225          20 :             tm->tm_year + STRUCT_TM_YEAR_OFFSET,
     226          20 :             tm->tm_mon + STRUCT_TM_MONTH_OFFSET,
     227          20 :             tm->tm_mday,
     228          20 :             tm->tm_hour,
     229          20 :             tm->tm_min,
     230          20 :             tm->tm_sec));
     231          20 :     time_t_to_struct_tm(&time, tm);
     232          20 : }
     233             : 
     234             : void
     235           4 : present_now(struct PresentNowStruct * result)
     236             : {
     237           4 :     assert(result != NULL);
     238             : #if defined(_POSIX_TIMERS) && !defined(__STRICT_ANSI__)
     239             :     struct timespec tp;
     240             : #endif
     241             : 
     242             :     INITIALIZE();
     243           4 :     if (is_test_time_set) {
     244           3 :         *result = test_time;
     245             :     } else {
     246             : #if defined(_POSIX_TIMERS) && !defined(__STRICT_ANSI__)
     247           1 :         clock_gettime(CLOCK_REALTIME, &tp);
     248           1 :         result->sec = tp.tv_sec;
     249           1 :         result->nsec = tp.tv_nsec;
     250             : #else
     251             :         result->sec = time(NULL);
     252             :         result->nsec = 0;
     253             : #endif
     254             :     }
     255             :     DONE();
     256           4 : }
     257             : 
     258             : void
     259           1 : present_set_test_time(struct PresentNowStruct value)
     260             : {
     261             :     INITIALIZE();
     262           1 :     is_test_time_set = 1;
     263           1 :     test_time = value;
     264             :     DONE();
     265           1 : }
     266             : 
     267             : void
     268           1 : present_reset_test_time()
     269             : {
     270             :     INITIALIZE();
     271           1 :     is_test_time_set = 0;
     272             :     DONE();
     273           1 : }
     274             : 

Generated by: LCOV version 1.10