aboutsummaryrefslogtreecommitdiffhomepage
path: root/absl/time/internal/cctz/src/time_zone_posix.cc
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2018-04-23 08:17:58 -0700
committerGravatar Derek Mauro <dmauro@google.com>2018-04-23 12:57:34 -0400
commitaf7882601aad93ada881486eeaabc562f1733961 (patch)
treee9a52b01ef69c7654a97d66c8d60377c851ae817 /absl/time/internal/cctz/src/time_zone_posix.cc
parent94ce52d46c171683b1ee22d14277a6d3bdfd7c4c (diff)
- fd5f3d7077270ffc5ea74cdb9e18bbae3b9b46aa Fix typo optional -> variant by Abseil Team <absl-team@google.com>
- 9136c06dfa8dbfdde0a427ad3509e34763d607a6 Fix string_view_test and str_cat_test build under MSVC de... by Derek Mauro <dmauro@google.com> - a463820f9441888f4368aa87328599e3209f9b07 Removes constexpr optional<T>::operator->(). This was don... by Abseil Team <absl-team@google.com> - 3bf78a7f126daafff329f7815d507422f1ca378d Remove dependencies on external CCTZ project. by Shaindel Schwartz <shaindel@google.com> - a4ae574a11b1ddf6e88459af3d638cf79aea7ecd Internal change by Jon Cohen <cohenjon@google.com> GitOrigin-RevId: fd5f3d7077270ffc5ea74cdb9e18bbae3b9b46aa Change-Id: I6ab8ab99863716fe9b2745a12ef285f7a6da6d1e
Diffstat (limited to 'absl/time/internal/cctz/src/time_zone_posix.cc')
-rw-r--r--absl/time/internal/cctz/src/time_zone_posix.cc155
1 files changed, 155 insertions, 0 deletions
diff --git a/absl/time/internal/cctz/src/time_zone_posix.cc b/absl/time/internal/cctz/src/time_zone_posix.cc
new file mode 100644
index 0000000..75ad8bc
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_posix.cc
@@ -0,0 +1,155 @@
+// 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.
+
+#include "time_zone_posix.h"
+
+#include <cstddef>
+#include <cstring>
+#include <limits>
+#include <string>
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+namespace {
+
+const char kDigits[] = "0123456789";
+
+const char* ParseInt(const char* p, int min, int max, int* vp) {
+ int value = 0;
+ const char* op = p;
+ const int kMaxInt = std::numeric_limits<int>::max();
+ for (; const char* dp = strchr(kDigits, *p); ++p) {
+ int d = static_cast<int>(dp - kDigits);
+ if (d >= 10) break; // '\0'
+ if (value > kMaxInt / 10) return nullptr;
+ value *= 10;
+ if (value > kMaxInt - d) return nullptr;
+ value += d;
+ }
+ if (p == op || value < min || value > max) return nullptr;
+ *vp = value;
+ return p;
+}
+
+// abbr = <.*?> | [^-+,\d]{3,}
+const char* ParseAbbr(const char* p, std::string* abbr) {
+ const char* op = p;
+ if (*p == '<') { // special zoneinfo <...> form
+ while (*++p != '>') {
+ if (*p == '\0') return nullptr;
+ }
+ abbr->assign(op + 1, static_cast<std::size_t>(p - op) - 1);
+ return ++p;
+ }
+ while (*p != '\0') {
+ if (strchr("-+,", *p)) break;
+ if (strchr(kDigits, *p)) break;
+ ++p;
+ }
+ if (p - op < 3) return nullptr;
+ abbr->assign(op, static_cast<std::size_t>(p - op));
+ return p;
+}
+
+// offset = [+|-]hh[:mm[:ss]] (aggregated into single seconds value)
+const char* ParseOffset(const char* p, int min_hour, int max_hour, int sign,
+ std::int_fast32_t* offset) {
+ if (p == nullptr) return nullptr;
+ if (*p == '+' || *p == '-') {
+ if (*p++ == '-') sign = -sign;
+ }
+ int hours = 0;
+ int minutes = 0;
+ int seconds = 0;
+
+ p = ParseInt(p, min_hour, max_hour, &hours);
+ if (p == nullptr) return nullptr;
+ if (*p == ':') {
+ p = ParseInt(p + 1, 0, 59, &minutes);
+ if (p == nullptr) return nullptr;
+ if (*p == ':') {
+ p = ParseInt(p + 1, 0, 59, &seconds);
+ if (p == nullptr) return nullptr;
+ }
+ }
+ *offset = sign * ((((hours * 60) + minutes) * 60) + seconds);
+ return p;
+}
+
+// datetime = ( Jn | n | Mm.w.d ) [ / offset ]
+const char* ParseDateTime(const char* p, PosixTransition* res) {
+ if (p != nullptr && *p == ',') {
+ if (*++p == 'M') {
+ int month = 0;
+ if ((p = ParseInt(p + 1, 1, 12, &month)) != nullptr && *p == '.') {
+ int week = 0;
+ if ((p = ParseInt(p + 1, 1, 5, &week)) != nullptr && *p == '.') {
+ int weekday = 0;
+ if ((p = ParseInt(p + 1, 0, 6, &weekday)) != nullptr) {
+ res->date.fmt = PosixTransition::M;
+ res->date.m.month = static_cast<int_fast8_t>(month);
+ res->date.m.week = static_cast<int_fast8_t>(week);
+ res->date.m.weekday = static_cast<int_fast8_t>(weekday);
+ }
+ }
+ }
+ } else if (*p == 'J') {
+ int day = 0;
+ if ((p = ParseInt(p + 1, 1, 365, &day)) != nullptr) {
+ res->date.fmt = PosixTransition::J;
+ res->date.j.day = static_cast<int_fast16_t>(day);
+ }
+ } else {
+ int day = 0;
+ if ((p = ParseInt(p, 0, 365, &day)) != nullptr) {
+ res->date.fmt = PosixTransition::N;
+ res->date.j.day = static_cast<int_fast16_t>(day);
+ }
+ }
+ }
+ if (p != nullptr) {
+ res->time.offset = 2 * 60 * 60; // default offset is 02:00:00
+ if (*p == '/') p = ParseOffset(p + 1, -167, 167, 1, &res->time.offset);
+ }
+ return p;
+}
+
+} // namespace
+
+// spec = std offset [ dst [ offset ] , datetime , datetime ]
+bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res) {
+ const char* p = spec.c_str();
+ if (*p == ':') return false;
+
+ p = ParseAbbr(p, &res->std_abbr);
+ p = ParseOffset(p, 0, 24, -1, &res->std_offset);
+ if (p == nullptr) return false;
+ if (*p == '\0') return true;
+
+ p = ParseAbbr(p, &res->dst_abbr);
+ if (p == nullptr) return false;
+ res->dst_offset = res->std_offset + (60 * 60); // default
+ if (*p != ',') p = ParseOffset(p, 0, 24, -1, &res->dst_offset);
+
+ p = ParseDateTime(p, &res->dst_start);
+ p = ParseDateTime(p, &res->dst_end);
+
+ return p != nullptr && *p == '\0';
+}
+
+} // namespace cctz
+} // namespace time_internal
+} // namespace absl