about summary refs log tree commit diff
path: root/absl/time/internal/cctz/src/time_zone_libc.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/time/internal/cctz/src/time_zone_libc.cc')
-rw-r--r--absl/time/internal/cctz/src/time_zone_libc.cc156
1 files changed, 156 insertions, 0 deletions
diff --git a/absl/time/internal/cctz/src/time_zone_libc.cc b/absl/time/internal/cctz/src/time_zone_libc.cc
new file mode 100644
index 0000000000..b0b56a5223
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_libc.cc
@@ -0,0 +1,156 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#if defined(_WIN32) || defined(_WIN64)
+#define _CRT_SECURE_NO_WARNINGS 1
+#endif
+
+#include "time_zone_libc.h"
+
+#include <chrono>
+#include <ctime>
+#include <tuple>
+#include <utility>
+
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+namespace {
+
+// .first is seconds east of UTC; .second is the time-zone abbreviation.
+using OffsetAbbr = std::pair<int, const char*>;
+
+// Defines a function that can be called as follows:
+//
+//   std::tm tm = ...;
+//   OffsetAbbr off_abbr = get_offset_abbr(tm);
+//
+#if defined(_WIN32) || defined(_WIN64)
+// Uses the globals: '_timezone', '_dstbias' and '_tzname'.
+OffsetAbbr get_offset_abbr(const std::tm& tm) {
+  const bool is_dst = tm.tm_isdst > 0;
+  const int off = _timezone + (is_dst ? _dstbias : 0);
+  const char* abbr = _tzname[is_dst];
+  return {off, abbr};
+}
+#elif defined(__sun)
+// Uses the globals: 'timezone', 'altzone' and 'tzname'.
+OffsetAbbr get_offset_abbr(const std::tm& tm) {
+  const bool is_dst = tm.tm_isdst > 0;
+  const int off = is_dst ? altzone : timezone;
+  const char* abbr = tzname[is_dst];
+  return {off, abbr};
+}
+#elif defined(__native_client__) || defined(__myriad2__) || \
+    defined(__EMSCRIPTEN__)
+// Uses the globals: 'timezone' and 'tzname'.
+OffsetAbbr get_offset_abbr(const std::tm& tm) {
+  const bool is_dst = tm.tm_isdst > 0;
+  const int off = _timezone + (is_dst ? 60 * 60 : 0);
+  const char* abbr = tzname[is_dst];
+  return {off, abbr};
+}
+#else
+//
+// Returns an OffsetAbbr using std::tm fields with various spellings.
+//
+#if !defined(tm_gmtoff) && !defined(tm_zone)
+template <typename T>
+OffsetAbbr get_offset_abbr(const T& tm, decltype(&T::tm_gmtoff) = nullptr,
+                           decltype(&T::tm_zone) = nullptr) {
+  return {tm.tm_gmtoff, tm.tm_zone};
+}
+#endif  // !defined(tm_gmtoff) && !defined(tm_zone)
+#if !defined(__tm_gmtoff) && !defined(__tm_zone)
+template <typename T>
+OffsetAbbr get_offset_abbr(const T& tm, decltype(&T::__tm_gmtoff) = nullptr,
+                           decltype(&T::__tm_zone) = nullptr) {
+  return {tm.__tm_gmtoff, tm.__tm_zone};
+}
+#endif  // !defined(__tm_gmtoff) && !defined(__tm_zone)
+#endif
+
+}  // namespace
+
+TimeZoneLibC::TimeZoneLibC(const std::string& name)
+    : local_(name == "localtime") {}
+
+time_zone::absolute_lookup TimeZoneLibC::BreakTime(
+    const time_point<sys_seconds>& tp) const {
+  time_zone::absolute_lookup al;
+  std::time_t t = ToUnixSeconds(tp);
+  std::tm tm;
+  if (local_) {
+#if defined(_WIN32) || defined(_WIN64)
+    localtime_s(&tm, &t);
+#else
+    localtime_r(&t, &tm);
+#endif
+    std::tie(al.offset, al.abbr) = get_offset_abbr(tm);
+  } else {
+#if defined(_WIN32) || defined(_WIN64)
+    gmtime_s(&tm, &t);
+#else
+    gmtime_r(&t, &tm);
+#endif
+    al.offset = 0;
+    al.abbr = "UTC";
+  }
+  al.cs = civil_second(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+                       tm.tm_hour, tm.tm_min, tm.tm_sec);
+  al.is_dst = tm.tm_isdst > 0;
+  return al;
+}
+
+time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const {
+  time_zone::civil_lookup cl;
+  std::time_t t;
+  if (local_) {
+    // Does not handle SKIPPED/AMBIGUOUS or huge years.
+    std::tm tm;
+    tm.tm_year = static_cast<int>(cs.year() - 1900);
+    tm.tm_mon = cs.month() - 1;
+    tm.tm_mday = cs.day();
+    tm.tm_hour = cs.hour();
+    tm.tm_min = cs.minute();
+    tm.tm_sec = cs.second();
+    tm.tm_isdst = -1;
+    t = std::mktime(&tm);
+  } else {
+    t = cs - civil_second();
+  }
+  cl.kind = time_zone::civil_lookup::UNIQUE;
+  cl.pre = cl.trans = cl.post = FromUnixSeconds(t);
+  return cl;
+}
+
+std::string TimeZoneLibC::Description() const {
+  return local_ ? "localtime" : "UTC";
+}
+
+bool TimeZoneLibC::NextTransition(time_point<sys_seconds>* tp) const {
+  return false;
+}
+
+bool TimeZoneLibC::PrevTransition(time_point<sys_seconds>* tp) const {
+  return false;
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl