00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #if defined(_WIN32) || defined(_WIN64)
00016 #define _CRT_SECURE_NO_WARNINGS 1
00017 #endif
00018
00019 #include "time_zone_libc.h"
00020
00021 #include <chrono>
00022 #include <ctime>
00023 #include <limits>
00024 #include <tuple>
00025 #include <utility>
00026
00027 #include "absl/time/internal/cctz/include/cctz/civil_time.h"
00028 #include "absl/time/internal/cctz/include/cctz/time_zone.h"
00029
00030 namespace absl {
00031 namespace time_internal {
00032 namespace cctz {
00033
00034 namespace {
00035
00036
00037 using OffsetAbbr = std::pair<int, const char*>;
00038
00039
00040
00041
00042
00043
00044 #if defined(_WIN32) || defined(_WIN64)
00045
00046 OffsetAbbr get_offset_abbr(const std::tm& tm) {
00047 const bool is_dst = tm.tm_isdst > 0;
00048 const int off = _timezone + (is_dst ? _dstbias : 0);
00049 const char* abbr = _tzname[is_dst];
00050 return {off, abbr};
00051 }
00052 #elif defined(__sun)
00053
00054 OffsetAbbr get_offset_abbr(const std::tm& tm) {
00055 const bool is_dst = tm.tm_isdst > 0;
00056 const int off = is_dst ? altzone : timezone;
00057 const char* abbr = tzname[is_dst];
00058 return {off, abbr};
00059 }
00060 #elif defined(__native_client__) || defined(__myriad2__) || \
00061 defined(__EMSCRIPTEN__)
00062
00063 OffsetAbbr get_offset_abbr(const std::tm& tm) {
00064 const bool is_dst = tm.tm_isdst > 0;
00065 const int off = _timezone + (is_dst ? 60 * 60 : 0);
00066 const char* abbr = tzname[is_dst];
00067 return {off, abbr};
00068 }
00069 #else
00070
00071
00072
00073 #if !defined(tm_gmtoff) && !defined(tm_zone)
00074 template <typename T>
00075 OffsetAbbr get_offset_abbr(const T& tm, decltype(&T::tm_gmtoff) = nullptr,
00076 decltype(&T::tm_zone) = nullptr) {
00077 return {tm.tm_gmtoff, tm.tm_zone};
00078 }
00079 #endif // !defined(tm_gmtoff) && !defined(tm_zone)
00080 #if !defined(__tm_gmtoff) && !defined(__tm_zone)
00081 template <typename T>
00082 OffsetAbbr get_offset_abbr(const T& tm, decltype(&T::__tm_gmtoff) = nullptr,
00083 decltype(&T::__tm_zone) = nullptr) {
00084 return {tm.__tm_gmtoff, tm.__tm_zone};
00085 }
00086 #endif // !defined(__tm_gmtoff) && !defined(__tm_zone)
00087 #endif
00088
00089 inline std::tm* gm_time(const std::time_t *timep, std::tm *result) {
00090 #if defined(_WIN32) || defined(_WIN64)
00091 return gmtime_s(result, timep) ? nullptr : result;
00092 #else
00093 return gmtime_r(timep, result);
00094 #endif
00095 }
00096
00097 inline std::tm* local_time(const std::time_t *timep, std::tm *result) {
00098 #if defined(_WIN32) || defined(_WIN64)
00099 return localtime_s(result, timep) ? nullptr : result;
00100 #else
00101 return localtime_r(timep, result);
00102 #endif
00103 }
00104
00105
00106
00107
00108 bool make_time(const civil_second& cs, int is_dst, std::time_t* t, int* off) {
00109 std::tm tm;
00110 tm.tm_year = static_cast<int>(cs.year() - year_t{1900});
00111 tm.tm_mon = cs.month() - 1;
00112 tm.tm_mday = cs.day();
00113 tm.tm_hour = cs.hour();
00114 tm.tm_min = cs.minute();
00115 tm.tm_sec = cs.second();
00116 tm.tm_isdst = is_dst;
00117 *t = std::mktime(&tm);
00118 if (*t == std::time_t{-1}) {
00119 std::tm tm2;
00120 const std::tm* tmp = local_time(t, &tm2);
00121 if (tmp == nullptr || tmp->tm_year != tm.tm_year ||
00122 tmp->tm_mon != tm.tm_mon || tmp->tm_mday != tm.tm_mday ||
00123 tmp->tm_hour != tm.tm_hour || tmp->tm_min != tm.tm_min ||
00124 tmp->tm_sec != tm.tm_sec) {
00125
00126 return false;
00127 }
00128 }
00129 *off = get_offset_abbr(tm).first;
00130 return true;
00131 }
00132
00133
00134
00135 std::time_t find_trans(std::time_t lo, std::time_t hi, int offset) {
00136 std::tm tm;
00137 while (lo + 1 != hi) {
00138 const std::time_t mid = lo + (hi - lo) / 2;
00139 if (std::tm* tmp = local_time(&mid, &tm)) {
00140 if (get_offset_abbr(*tmp).first == offset) {
00141 hi = mid;
00142 } else {
00143 lo = mid;
00144 }
00145 } else {
00146
00147
00148 while (++lo != hi) {
00149 if (std::tm* tmp = local_time(&lo, &tm)) {
00150 if (get_offset_abbr(*tmp).first == offset) break;
00151 }
00152 }
00153 return lo;
00154 }
00155 }
00156 return hi;
00157 }
00158
00159 }
00160
00161 TimeZoneLibC::TimeZoneLibC(const std::string& name)
00162 : local_(name == "localtime") {}
00163
00164 time_zone::absolute_lookup TimeZoneLibC::BreakTime(
00165 const time_point<seconds>& tp) const {
00166 time_zone::absolute_lookup al;
00167 al.offset = 0;
00168 al.is_dst = false;
00169 al.abbr = "-00";
00170
00171 const std::int_fast64_t s = ToUnixSeconds(tp);
00172
00173
00174 if (s < std::numeric_limits<std::time_t>::min()) {
00175 al.cs = civil_second::min();
00176 return al;
00177 }
00178 if (s > std::numeric_limits<std::time_t>::max()) {
00179 al.cs = civil_second::max();
00180 return al;
00181 }
00182
00183 const std::time_t t = static_cast<std::time_t>(s);
00184 std::tm tm;
00185 std::tm* tmp = local_ ? local_time(&t, &tm) : gm_time(&t, &tm);
00186
00187
00188 if (tmp == nullptr) {
00189 al.cs = (s < 0) ? civil_second::min() : civil_second::max();
00190 return al;
00191 }
00192
00193 const year_t year = tmp->tm_year + year_t{1900};
00194 al.cs = civil_second(year, tmp->tm_mon + 1, tmp->tm_mday,
00195 tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
00196 std::tie(al.offset, al.abbr) = get_offset_abbr(*tmp);
00197 if (!local_) al.abbr = "UTC";
00198 al.is_dst = tmp->tm_isdst > 0;
00199 return al;
00200 }
00201
00202 time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const {
00203 if (!local_) {
00204
00205 static const civil_second min_tp_cs =
00206 civil_second() + ToUnixSeconds(time_point<seconds>::min());
00207 static const civil_second max_tp_cs =
00208 civil_second() + ToUnixSeconds(time_point<seconds>::max());
00209 const time_point<seconds> tp =
00210 (cs < min_tp_cs)
00211 ? time_point<seconds>::min()
00212 : (cs > max_tp_cs) ? time_point<seconds>::max()
00213 : FromUnixSeconds(cs - civil_second());
00214 return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
00215 }
00216
00217
00218 if (cs.year() < 0) {
00219 if (cs.year() < std::numeric_limits<int>::min() + year_t{1900}) {
00220 const time_point<seconds> tp = time_point<seconds>::min();
00221 return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
00222 }
00223 } else {
00224 if (cs.year() - year_t{1900} > std::numeric_limits<int>::max()) {
00225 const time_point<seconds> tp = time_point<seconds>::max();
00226 return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
00227 }
00228 }
00229
00230
00231
00232
00233
00234 std::time_t t0, t1;
00235 int offset0, offset1;
00236 if (make_time(cs, 0, &t0, &offset0) && make_time(cs, 1, &t1, &offset1)) {
00237 if (t0 == t1) {
00238
00239 const time_point<seconds> tp = FromUnixSeconds(t0);
00240 return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
00241 }
00242
00243 if (t0 > t1) {
00244 std::swap(t0, t1);
00245 std::swap(offset0, offset1);
00246 }
00247 const std::time_t tt = find_trans(t0, t1, offset1);
00248 const time_point<seconds> trans = FromUnixSeconds(tt);
00249
00250 if (offset0 < offset1) {
00251
00252 const time_point<seconds> pre = FromUnixSeconds(t1);
00253 const time_point<seconds> post = FromUnixSeconds(t0);
00254 return {time_zone::civil_lookup::SKIPPED, pre, trans, post};
00255 }
00256
00257
00258 const time_point<seconds> pre = FromUnixSeconds(t0);
00259 const time_point<seconds> post = FromUnixSeconds(t1);
00260 return {time_zone::civil_lookup::REPEATED, pre, trans, post};
00261 }
00262
00263
00264 const time_point<seconds> tp = (cs < civil_second())
00265 ? time_point<seconds>::min()
00266 : time_point<seconds>::max();
00267 return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
00268 }
00269
00270 bool TimeZoneLibC::NextTransition(const time_point<seconds>&,
00271 time_zone::civil_transition*) const {
00272 return false;
00273 }
00274
00275 bool TimeZoneLibC::PrevTransition(const time_point<seconds>&,
00276 time_zone::civil_transition*) const {
00277 return false;
00278 }
00279
00280 std::string TimeZoneLibC::Version() const {
00281 return std::string();
00282 }
00283
00284 std::string TimeZoneLibC::Description() const {
00285 return local_ ? "localtime" : "UTC";
00286 }
00287
00288 }
00289 }
00290 }