LCOV - code coverage report
Current view: top level - util - time_utilities.cc (source / functions) Hit Total Coverage
Test: report.info Lines: 76 76 100.0 %
Date: 2012-05-15 Functions: 7 7 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 111 134 82.8 %

           Branch data     Line data    Source code
       1                 :            : // Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
       2                 :            : //
       3                 :            : // Permission to use, copy, modify, and/or distribute this software for any
       4                 :            : // purpose with or without fee is hereby granted, provided that the above
       5                 :            : // copyright notice and this permission notice appear in all copies.
       6                 :            : //
       7                 :            : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
       8                 :            : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
       9                 :            : // AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
      10                 :            : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
      11                 :            : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
      12                 :            : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
      13                 :            : // PERFORMANCE OF THIS SOFTWARE.
      14                 :            : 
      15                 :            : #include <stdint.h>
      16                 :            : 
      17                 :            : #include <sys/time.h>
      18                 :            : 
      19                 :            : #include <string>
      20                 :            : #include <iomanip>
      21                 :            : #include <iostream>
      22                 :            : #include <sstream>
      23                 :            : 
      24                 :            : #include <stdio.h>
      25                 :            : #include <time.h>
      26                 :            : 
      27                 :            : #include <exceptions/exceptions.h>
      28                 :            : 
      29                 :            : #include <util/time_utilities.h>
      30                 :            : 
      31                 :            : using namespace std;
      32                 :            : 
      33                 :            : namespace {
      34                 :            : int days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
      35                 :            : 
      36                 :            : inline bool
      37                 :            : isLeap(const int y) {
      38 [ +  + ][ +  + ]:     555679 :     return ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0);
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  - ]
                 [ +  + ]
      39                 :            : }
      40                 :            : 
      41                 :            : unsigned int
      42                 :            : yearSecs(const int year) {
      43         [ +  + ]:      82699 :     return ((isLeap(year) ? 366 : 365 ) * 86400);
      44                 :            : }
      45                 :            : 
      46                 :            : unsigned int
      47                 :            : monthSecs(const int month, const int year) {
      48 [ +  + ][ +  + ]:       3966 :     return ((days[month] + ((month == 1 && isLeap(year)) ? 1 : 0 )) * 86400);
      49                 :            : }
      50                 :            : }
      51                 :            : 
      52                 :            : namespace isc {
      53                 :            : namespace util {
      54                 :            : 
      55                 :            : string
      56                 :       1503 : timeToText64(uint64_t value) {
      57                 :            :     struct tm tm;
      58                 :            :     unsigned int secs;
      59                 :            : 
      60                 :            :     // We cannot rely on gmtime() because time_t may not be of 64 bit
      61                 :            :     // integer.  The following conversion logic is borrowed from BIND 9.
      62                 :       1503 :     tm.tm_year = 70;
      63         [ +  + ]:      84202 :     while ((secs = yearSecs(tm.tm_year + 1900)) <= value) {
      64                 :      81198 :         value -= secs;
      65                 :      81198 :         ++tm.tm_year;
      66         [ +  + ]:      81198 :         if (tm.tm_year + 1900 > 9999) {
      67 [ +  - ][ +  - ]:          4 :             isc_throw(InvalidTime,
                 [ +  - ]
      68                 :            :                       "Time value out of range (year > 9999): " <<
      69                 :            :                       tm.tm_year + 1900);
      70                 :            :         }
      71                 :            :     }
      72                 :       1501 :     tm.tm_mon = 0;
      73         [ +  + ]:       4534 :     while ((secs = monthSecs(tm.tm_mon, tm.tm_year + 1900)) <= value) {
      74                 :       1532 :         value -= secs;
      75                 :       1532 :         tm.tm_mon++;
      76                 :            :     }
      77                 :       1501 :     tm.tm_mday = 1;
      78         [ +  + ]:       8787 :     while (86400 <= value) {
      79                 :       7286 :         value -= 86400;
      80                 :       7286 :         ++tm.tm_mday;
      81                 :            :     }
      82                 :       1501 :     tm.tm_hour = 0;
      83         [ +  + ]:       5115 :     while (3600 <= value) {
      84                 :       3614 :         value -= 3600;
      85                 :       3614 :         ++tm.tm_hour;
      86                 :            :     }
      87                 :       1501 :     tm.tm_min = 0;
      88         [ +  + ]:      16452 :     while (60 <= value) {
      89                 :      14951 :         value -= 60;
      90                 :      14951 :         ++tm.tm_min;
      91                 :            :     }
      92                 :       1501 :     tm.tm_sec = value;    // now t < 60, so this substitution is safe.
      93                 :            : 
      94                 :       3002 :     ostringstream oss;
      95         [ +  - ]:       1501 :     oss << setfill('0')
      96         [ +  - ]:       1501 :         << setw(4) << tm.tm_year + 1900
      97         [ +  - ]:       1501 :         << setw(2) << tm.tm_mon + 1
      98         [ +  - ]:       1501 :         << setw(2) << tm.tm_mday
      99         [ +  - ]:       1501 :         << setw(2) << tm.tm_hour
     100         [ +  - ]:       1501 :         << setw(2) << tm.tm_min
     101         [ +  - ]:       1501 :         << setw(2) << tm.tm_sec;
     102                 :       1501 :     return (oss.str());
     103                 :            : }
     104                 :            : 
     105                 :            : // timeToText32() below uses the current system time.  To test it with
     106                 :            : // unusual current time values we introduce the following function pointer;
     107                 :            : // when it's non NULL, we call it to get the (normally faked) current time.
     108                 :            : // Otherwise we use the standard gettimeofday(2).  This hook is specifically
     109                 :            : // intended for testing purposes, so, even if it's visible outside of this
     110                 :            : // library, it's not even declared in a header file.
     111                 :            : namespace detail {
     112                 :            : int64_t (*gettimeFunction)() = NULL;
     113                 :            : 
     114                 :            : int64_t
     115                 :       1775 : gettimeWrapper() {
     116         [ +  + ]:       1775 :     if (gettimeFunction != NULL) {
     117                 :        115 :         return (gettimeFunction());
     118                 :            :     }
     119                 :            : 
     120                 :            :     struct timeval now;
     121                 :       1660 :     gettimeofday(&now, NULL);
     122                 :            : 
     123                 :       1775 :     return (static_cast<int64_t>(now.tv_sec));
     124                 :            : }
     125                 :            : }
     126                 :            : 
     127                 :            : string
     128                 :       1499 : timeToText32(const uint32_t value) {
     129                 :            :     // We first adjust the time to the closest epoch based on the current time.
     130                 :            :     // Note that the following variables must be signed in order to handle
     131                 :            :     // time until year 2038 correctly.
     132                 :       1499 :     const int64_t start = detail::gettimeWrapper() - 0x7fffffff;
     133                 :       1499 :     int64_t base = 0;
     134                 :            :     int64_t t;
     135         [ +  + ]:       1616 :     while ((t = (base + value)) < start) {
     136                 :        117 :         base += 0x100000000LL;
     137                 :            :     }
     138                 :            : 
     139                 :            :     // Then convert it to text.
     140                 :       1499 :     return (timeToText64(t));
     141                 :            : }
     142                 :            : 
     143                 :            : namespace {
     144                 :            : const size_t DATE_LEN = 14;      // YYYYMMDDHHmmSS
     145                 :            : 
     146                 :            : inline void
     147                 :      85955 : checkRange(const int min, const int max, const int value,
     148                 :            :            const string& valname)
     149                 :            : {
     150         [ +  + ]:      85955 :     if ((value >= min) && (value <= max)) {
     151                 :      85944 :         return;
     152                 :            :     }
     153 [ +  - ][ +  - ]:         22 :     isc_throw(InvalidTime, "Invalid " << valname << "value: " << value);
         [ +  - ][ +  - ]
                 [ +  - ]
     154                 :            : }
     155                 :            : }
     156                 :            : 
     157                 :            : uint64_t
     158                 :      14335 : timeFromText64(const string& time_txt) {
     159                 :            :     // Confirm the source only consists digits.  sscanf() allows some
     160                 :            :     // minor exceptions.
     161         [ +  + ]:     215001 :     for (string::size_type i = 0; i < time_txt.length(); ++i) {
     162         [ +  + ]:     200668 :         if (!isdigit(time_txt.at(i))) {
     163 [ +  - ][ +  - ]:          4 :             isc_throw(InvalidTime, "Couldn't convert non-numeric time value: "
                 [ +  - ]
     164                 :            :                       << time_txt);
     165                 :            :         }
     166                 :            :     }
     167                 :            : 
     168                 :            :     int year, month, day, hour, minute, second;
     169 [ +  + ][ -  + ]:      14333 :     if (time_txt.length() != DATE_LEN ||
                 [ +  + ]
     170                 :            :         sscanf(time_txt.c_str(), "%4d%2d%2d%2d%2d%2d",
     171                 :      14331 :                &year, &month, &day, &hour, &minute, &second) != 6)
     172                 :            :     {
     173 [ +  - ][ +  - ]:          4 :         isc_throw(InvalidTime, "Couldn't convert time value: " << time_txt);
                 [ +  - ]
     174                 :            :     }
     175                 :            : 
     176         [ +  + ]:      14331 :     checkRange(1970, 9999, year, "year");
     177         [ +  + ]:      14330 :     checkRange(1, 12, month, "month");
     178                 :      20990 :     checkRange(1, days[month - 1] + ((month == 2 && isLeap(year)) ? 1 : 0),
     179 [ +  + ][ +  + ]:      20990 :             day, "day");
                 [ +  + ]
     180         [ +  + ]:      14323 :     checkRange(0, 23, hour, "hour");
     181         [ +  + ]:      14322 :     checkRange(0, 59, minute, "minute");
     182         [ +  + ]:      14321 :     checkRange(0, 60, second, "second"); // 60 == leap second.
     183                 :            : 
     184                 :            :     uint64_t timeval = second + (60 * minute) + (3600 * hour) +
     185                 :      14320 :         ((day - 1) * 86400);
     186         [ +  + ]:      28064 :     for (int m = 0; m < (month - 1); ++m) {
     187                 :      13744 :             timeval += days[m] * 86400;
     188                 :            :     }
     189 [ +  + ][ +  + ]:      14320 :     if (isLeap(year) && month > 2) {
                 [ +  + ]
     190                 :      14320 :             timeval += 86400;
     191                 :            :     }
     192         [ +  + ]:     465385 :     for (int y = 1970; y < year; ++y) {
     193         [ +  + ]:     451065 :         timeval += ((isLeap(y) ? 366 : 365 ) * 86400);
     194                 :            :     }
     195                 :            : 
     196                 :      14320 :     return (timeval);
     197                 :            : }
     198                 :            : 
     199                 :            : uint32_t
     200                 :      14333 : timeFromText32(const string& time_txt) {
     201                 :            :     // The implicit conversion from uint64_t to uint32_t should just work here,
     202                 :            :     // because we only need to drop higher 32 bits.
     203                 :      14333 :     return (timeFromText64(time_txt));
     204                 :            : }
     205                 :            : 
     206                 :            : }
     207                 :        169 : }

Generated by: LCOV version 1.9