diff options
Diffstat (limited to '')
-rw-r--r-- | src/base/time_util.cc | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/src/base/time_util.cc b/src/base/time_util.cc new file mode 100644 index 0000000..0d46107 --- /dev/null +++ b/src/base/time_util.cc @@ -0,0 +1,239 @@ +/** + * Copyright (c) 2020, Timothy Stack + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Timothy Stack nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @file time_util.cc + */ + +#include <chrono> + +#include "time_util.hh" + +#include "config.h" + +namespace lnav { + +ssize_t +strftime_rfc3339( + char* buffer, size_t buffer_size, lnav::time64_t tim, int millis, char sep) +{ + struct tm gmtm; + int year, month, index = 0; + + secs2tm(tim, &gmtm); + year = gmtm.tm_year + 1900; + month = gmtm.tm_mon + 1; + buffer[index++] = '0' + ((year / 1000) % 10); + buffer[index++] = '0' + ((year / 100) % 10); + buffer[index++] = '0' + ((year / 10) % 10); + buffer[index++] = '0' + ((year / 1) % 10); + buffer[index++] = '-'; + buffer[index++] = '0' + ((month / 10) % 10); + buffer[index++] = '0' + ((month / 1) % 10); + buffer[index++] = '-'; + buffer[index++] = '0' + ((gmtm.tm_mday / 10) % 10); + buffer[index++] = '0' + ((gmtm.tm_mday / 1) % 10); + buffer[index++] = sep; + buffer[index++] = '0' + ((gmtm.tm_hour / 10) % 10); + buffer[index++] = '0' + ((gmtm.tm_hour / 1) % 10); + buffer[index++] = ':'; + buffer[index++] = '0' + ((gmtm.tm_min / 10) % 10); + buffer[index++] = '0' + ((gmtm.tm_min / 1) % 10); + buffer[index++] = ':'; + buffer[index++] = '0' + ((gmtm.tm_sec / 10) % 10); + buffer[index++] = '0' + ((gmtm.tm_sec / 1) % 10); + buffer[index++] = '.'; + buffer[index++] = '0' + ((millis / 100) % 10); + buffer[index++] = '0' + ((millis / 10) % 10); + buffer[index++] = '0' + ((millis / 1) % 10); + buffer[index] = '\0'; + + return index; +} + +} + +static time_t BAD_DATE = -1; + +time_t +tm2sec(const struct tm* t) +{ + int year; + time_t days, secs; + const int dayoffset[12] + = {306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275}; + + year = t->tm_year; + + if (year < 70) { + return BAD_DATE; + } + if ((sizeof(time_t) <= 4) && (year >= 138)) { + year = 137; + } + + /* shift new year to 1st March in order to make leap year calc easy */ + + if (t->tm_mon < 2) { + year--; + } + + /* Find number of days since 1st March 1900 (in the Gregorian calendar). */ + + days = year * 365 + year / 4 - year / 100 + (year / 100 + 3) / 4; + days += dayoffset[t->tm_mon] + t->tm_mday - 1; + days -= 25508; /* 1 jan 1970 is 25508 days since 1 mar 1900 */ + + secs = ((days * 24 + t->tm_hour) * 60 + t->tm_min) * 60 + t->tm_sec; + + if (secs < 0) { + return BAD_DATE; + } /* must have overflowed */ + else + { +#ifdef HAVE_STRUCT_TM_TM_ZONE + if (t->tm_zone) { + secs -= t->tm_gmtoff; + } +#endif + return secs; + } /* must be a valid time */ +} + +static const int SECSPERMIN = 60; +static const int SECSPERHOUR = 60 * SECSPERMIN; +static const int SECSPERDAY = 24 * SECSPERHOUR; +static const int YEAR_BASE = 1900; +static const int EPOCH_WDAY = 4; +static const int DAYSPERWEEK = 7; +static const int EPOCH_YEAR = 1970; + +#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) + +static const int year_lengths[2] = {365, 366}; + +const unsigned short int mon_yday[2][13] = { + /* Normal years. */ + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, + /* Leap years. */ + {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}}; + +void +secs2wday(const struct timeval& tv, struct tm* res) +{ + long days, rem; + time_t lcltime; + + /* base decision about std/dst time on current time */ + lcltime = tv.tv_sec; + + days = ((long) lcltime) / SECSPERDAY; + rem = ((long) lcltime) % SECSPERDAY; + while (rem < 0) { + rem += SECSPERDAY; + --days; + } + + /* compute day of week */ + if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0) { + res->tm_wday += DAYSPERWEEK; + } +} + +struct tm* +secs2tm(lnav::time64_t tim, struct tm* res) +{ + long days, rem; + lnav::time64_t lcltime; + int y; + int yleap; + const unsigned short int* ip; + + /* base decision about std/dst time on current time */ + lcltime = tim; + + days = ((long) lcltime) / SECSPERDAY; + rem = ((long) lcltime) % SECSPERDAY; + while (rem < 0) { + rem += SECSPERDAY; + --days; + } + + /* compute hour, min, and sec */ + res->tm_hour = (int) (rem / SECSPERHOUR); + rem %= SECSPERHOUR; + res->tm_min = (int) (rem / SECSPERMIN); + res->tm_sec = (int) (rem % SECSPERMIN); + + /* compute day of week */ + if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0) + res->tm_wday += DAYSPERWEEK; + + /* compute year & day of year */ + y = EPOCH_YEAR; + if (days >= 0) { + for (;;) { + yleap = isleap(y); + if (days < year_lengths[yleap]) + break; + y++; + days -= year_lengths[yleap]; + } + } else { + do { + --y; + yleap = isleap(y); + days += year_lengths[yleap]; + } while (days < 0); + } + + res->tm_year = y - YEAR_BASE; + res->tm_yday = days; + ip = mon_yday[isleap(y)]; + for (y = 11; days < (long int) ip[y]; --y) + continue; + days -= ip[y]; + res->tm_mon = y; + res->tm_mday = days + 1; + + res->tm_isdst = 0; + + return (res); +} + +struct timeval +exttm::to_timeval() const +{ + struct timeval retval; + + retval.tv_sec = tm2sec(&this->et_tm); + retval.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>( + std::chrono::nanoseconds(this->et_nsec)) + .count(); + + return retval; +} |