OmniSciDB  06b3bd477c
 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 #include <regex>
40 #include <string>
41 
42 /* Number of days per month (except for February in leap years). */
43 // static const int monoff[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
44 
45 int TimeGM::is_leap_year(int year) {
46  return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
47 }
48 
49 int TimeGM::leap_days(int y1, int y2) {
50  --y1;
51  --y2;
52  return (y2 / 4 - y1 / 4) - (y2 / 100 - y1 / 100) + (y2 / 400 - y1 / 400);
53 }
54 
55 time_t TimeGM::parse_fractional_seconds(uint64_t sfrac,
56  const int32_t ntotal,
57  const int32_t dimen) {
58  int nfrac = log10(sfrac) + 1;
59  if (ntotal - nfrac > dimen) {
60  return 0;
61  }
62  if (ntotal >= 0 && ntotal < dimen) {
63  sfrac *= pow(10, dimen - ntotal);
64  } else if (ntotal > dimen) {
65  sfrac /= pow(10, ntotal - dimen);
66  }
67  return sfrac;
68 }
69 
70 time_t TimeGM::parse_meridians(const time_t& timeval,
71  const char* p,
72  const uint32_t hour,
73  const int32_t dimen) {
74  std::string time_str(p);
75  std::transform(time_str.begin(), time_str.end(), time_str.begin(), ::tolower);
76 
77  static std::regex pm_regex("(p[.]?m[.]?)");
78  std::smatch pm_match;
79  if (std::regex_search(time_str, pm_match, pm_regex)) {
80  return hour == 12 ? timeval
81  : timeval + kSecsPerHalfDay * static_cast<int64_t>(pow(10, dimen));
82  }
83 
84  static std::regex am_regex("(a[.]?m[.]?)");
85  std::smatch am_match;
86  if (std::regex_search(time_str, am_match, am_regex)) {
87  return hour == 12 ? timeval - kSecsPerHalfDay * static_cast<int64_t>(pow(10, dimen))
88  : timeval;
89  }
90 
91  return timeval;
92 }
93 
94 /*
95  * Code adapted from Python 2.4.1 sources (Lib/calendar.py).
96  */
97 time_t TimeGM::my_timegm_days(tm const* tm) {
98  int32_t year;
99  time_t days;
100  year = 1900 + tm->tm_year;
101  days = 365 * (year - 1970) + leap_days(1970, year);
102  days += monoff[tm->tm_mon];
103  if (tm->tm_mon > 1 && is_leap_year(year)) {
104  ++days;
105  }
106  days += tm->tm_mday - 1;
107  return days;
108 }
109 
110 time_t TimeGM::my_timegm(tm const* tm) {
111  time_t days;
112  time_t hours;
113  time_t minutes;
114  time_t seconds;
115 
116  days = my_timegm_days(tm);
117  hours = days * 24 + tm->tm_hour;
118  minutes = hours * 60 + tm->tm_min;
119  seconds = minutes * 60 + tm->tm_sec;
120 
121  seconds -= tm->tm_gmtoff;
122 
123  return seconds;
124 }
125 
127  const time_t fsc,
128  const int32_t dimen) {
129  const time_t epoch_seconds = my_timegm(tm);
130  const time_t epoch_scaled = epoch_seconds * static_cast<int64_t>(pow(10, dimen));
131  if (epoch_seconds &&
132  epoch_seconds != epoch_scaled / static_cast<int64_t>(pow(10, dimen))) {
133  throw std::runtime_error("Value out of range for TIMESTAMP(" + std::to_string(dimen) +
134  ").");
135  }
136  const time_t epoch_total = epoch_scaled + fsc;
137  if ((epoch_seconds > 0 && epoch_total < 0) || (epoch_seconds < 0 && epoch_total > 0)) {
138  throw std::runtime_error("Value out of range for TIMESTAMP(" + std::to_string(dimen) +
139  ").");
140  }
141 
142  return epoch_total;
143 }
144 
145 time_t TimeGM::my_timegm(tm const* tm, const time_t fsc, const int32_t dimen) {
146  return get_overflow_underflow_safe_epoch(tm, fsc, dimen);
147 }
int leap_days(int y1, int y2)
Definition: timegm.cpp:49
int is_leap_year(int year)
Definition: timegm.cpp:45
time_t get_overflow_underflow_safe_epoch(tm const *tm, const time_t fsc, const int32_t dimen)
Definition: timegm.cpp:126
time_t parse_meridians(const time_t &timeval, const char *p, const uint32_t hour, const int32_t dimen)
Definition: timegm.cpp:70
time_t parse_fractional_seconds(uint64_t sfrac, const int32_t ntotal, const int32_t dimen)
Definition: timegm.cpp:55
time_t my_timegm(tm const *tm)
Definition: timegm.cpp:110
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:97