OmniSciDB  1dac507f6e
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
timegm.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
3  *
4  * This software is open source.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * Redistributions of source code must retain the above copyright notice,
11  * this list of conditions and the following disclaimer.
12  *
13  * Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following disclaimer in the documentation
15  * and/or other materials provided with the distribution.
16  *
17  * Neither the name of the NLNET LABS nor the names of its contributors may
18  * be used to endorse or promote products derived from this software without
19  * specific prior written permission.
20 
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "TimeGM.h"
35 #include <boost/algorithm/string.hpp>
36 #include <cmath>
37 #include <ctime>
38 
39 /* Number of days per month (except for February in leap years). */
40 // static const int monoff[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
41 
42 int TimeGM::is_leap_year(int year) {
43  return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
44 }
45 
46 int TimeGM::leap_days(int y1, int y2) {
47  --y1;
48  --y2;
49  return (y2 / 4 - y1 / 4) - (y2 / 100 - y1 / 100) + (y2 / 400 - y1 / 400);
50 }
51 
52 time_t TimeGM::parse_fractional_seconds(uint64_t sfrac,
53  const int32_t ntotal,
54  const int32_t dimen) {
55  int nfrac = log10(sfrac) + 1;
56  if (ntotal - nfrac > dimen) {
57  return 0;
58  }
59  if (ntotal >= 0 && ntotal < dimen) {
60  sfrac *= pow(10, dimen - ntotal);
61  } else if (ntotal > dimen) {
62  sfrac /= pow(10, ntotal - dimen);
63  }
64  return sfrac;
65 }
66 
67 time_t TimeGM::parse_meridians(const time_t& timeval,
68  const char* p,
69  const uint32_t hour,
70  const int32_t dimen) {
71  char meridies[20];
72  if (sscanf(p, "%*d %s", meridies) != 1) {
73  if (sscanf(p, "%s", meridies) != 1) {
74  return timeval;
75  };
76  }
77  if (boost::iequals(std::string(meridies), "pm") ||
78  boost::iequals(std::string(meridies), "p.m.") ||
79  boost::iequals(std::string(meridies), "p.m")) {
80  return hour == 12 ? timeval
81  : timeval + kSecsPerHalfDay * static_cast<int64_t>(pow(10, dimen));
82  } else if (boost::iequals(std::string(meridies), "am") ||
83  boost::iequals(std::string(meridies), "a.m.") ||
84  boost::iequals(std::string(meridies), "a.m")) {
85  return hour == 12 ? timeval - kSecsPerHalfDay * static_cast<int64_t>(pow(10, dimen))
86  : timeval;
87  } else {
88  return timeval;
89  }
90 }
91 
92 /*
93  * Code adapted from Python 2.4.1 sources (Lib/calendar.py).
94  */
95 time_t TimeGM::my_timegm_days(tm const* tm) {
96  int32_t year;
97  time_t days;
98  year = 1900 + tm->tm_year;
99  days = 365 * (year - 1970) + leap_days(1970, year);
100  days += monoff[tm->tm_mon];
101  if (tm->tm_mon > 1 && is_leap_year(year)) {
102  ++days;
103  }
104  days += tm->tm_mday - 1;
105  return days;
106 }
107 
108 time_t TimeGM::my_timegm(tm const* tm) {
109  time_t days;
110  time_t hours;
111  time_t minutes;
112  time_t seconds;
113 
114  days = my_timegm_days(tm);
115  hours = days * 24 + tm->tm_hour;
116  minutes = hours * 60 + tm->tm_min;
117  seconds = minutes * 60 + tm->tm_sec;
118 
119  seconds -= tm->tm_gmtoff;
120 
121  return seconds;
122 }
123 
125  const time_t fsc,
126  const int32_t dimen) {
127  const time_t epoch_seconds = my_timegm(tm);
128  const time_t epoch_scaled = epoch_seconds * static_cast<int64_t>(pow(10, dimen));
129  if (epoch_seconds &&
130  epoch_seconds != epoch_scaled / static_cast<int64_t>(pow(10, dimen))) {
131  throw std::runtime_error("Value out of range for TIMESTAMP(" + std::to_string(dimen) +
132  ").");
133  }
134  const time_t epoch_total = epoch_scaled + fsc;
135  if ((epoch_seconds > 0 && epoch_total < 0) || (epoch_seconds < 0 && epoch_total > 0)) {
136  throw std::runtime_error("Value out of range for TIMESTAMP(" + std::to_string(dimen) +
137  ").");
138  }
139 
140  return epoch_total;
141 }
142 
143 time_t TimeGM::my_timegm(tm const* tm, const time_t fsc, const int32_t dimen) {
144  return get_overflow_underflow_safe_epoch(tm, fsc, dimen);
145 }
int leap_days(int y1, int y2)
Definition: timegm.cpp:46
int is_leap_year(int year)
Definition: timegm.cpp:42
time_t get_overflow_underflow_safe_epoch(tm const *tm, const time_t fsc, const int32_t dimen)
Definition: timegm.cpp:124
time_t parse_meridians(const time_t &timeval, const char *p, const uint32_t hour, const int32_t dimen)
Definition: timegm.cpp:67
time_t parse_fractional_seconds(uint64_t sfrac, const int32_t ntotal, const int32_t dimen)
Definition: timegm.cpp:52
time_t my_timegm(tm const *tm)
Definition: timegm.cpp:108
std::string to_string(char const *&&v)
static constexpr int64_t kSecsPerHalfDay
const int monoff[12]
Definition: TimeGM.h:55
time_t my_timegm_days(tm const *tm)
Definition: timegm.cpp:95