summaryrefslogtreecommitdiff
path: root/absl/time/internal/cctz/src/time_zone_fixed.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/time/internal/cctz/src/time_zone_fixed.cc')
-rw-r--r--absl/time/internal/cctz/src/time_zone_fixed.cc133
1 files changed, 133 insertions, 0 deletions
diff --git a/absl/time/internal/cctz/src/time_zone_fixed.cc b/absl/time/internal/cctz/src/time_zone_fixed.cc
new file mode 100644
index 00000000..8d3b1442
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_fixed.cc
@@ -0,0 +1,133 @@
+// 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_fixed.h"
+
+#include <algorithm>
+#include <chrono>
+#include <cstdio>
+#include <cstring>
+#include <string>
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+namespace {
+
+// The prefix used for the internal names of fixed-offset zones.
+const char kFixedOffsetPrefix[] = "Fixed/";
+
+int Parse02d(const char* p) {
+ static const char kDigits[] = "0123456789";
+ if (const char* ap = std::strchr(kDigits, *p)) {
+ int v = static_cast<int>(ap - kDigits);
+ if (const char* bp = std::strchr(kDigits, *++p)) {
+ return (v * 10) + static_cast<int>(bp - kDigits);
+ }
+ }
+ return -1;
+}
+
+} // namespace
+
+bool FixedOffsetFromName(const std::string& name, sys_seconds* offset) {
+ if (name.compare(0, std::string::npos, "UTC", 3) == 0) {
+ *offset = sys_seconds::zero();
+ return true;
+ }
+
+ const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
+ const char* const ep = kFixedOffsetPrefix + prefix_len;
+ if (name.size() != prefix_len + 12) // "<prefix>UTC+99:99:99"
+ return false;
+ if (!std::equal(kFixedOffsetPrefix, ep, name.begin()))
+ return false;
+ const char* np = name.data() + prefix_len;
+ if (*np++ != 'U' || *np++ != 'T' || *np++ != 'C')
+ return false;
+ if (np[0] != '+' && np[0] != '-')
+ return false;
+ if (np[3] != ':' || np[6] != ':') // see note below about large offsets
+ return false;
+
+ int hours = Parse02d(np + 1);
+ if (hours == -1) return false;
+ int mins = Parse02d(np + 4);
+ if (mins == -1) return false;
+ int secs = Parse02d(np + 7);
+ if (secs == -1) return false;
+
+ secs += ((hours * 60) + mins) * 60;
+ if (secs > 24 * 60 * 60) return false; // outside supported offset range
+ *offset = sys_seconds(secs * (np[0] == '-' ? -1 : 1)); // "-" means west
+ return true;
+}
+
+std::string FixedOffsetToName(const sys_seconds& offset) {
+ if (offset == sys_seconds::zero()) return "UTC";
+ if (offset < std::chrono::hours(-24) || offset > std::chrono::hours(24)) {
+ // We don't support fixed-offset zones more than 24 hours
+ // away from UTC to avoid complications in rendering such
+ // offsets and to (somewhat) limit the total number of zones.
+ return "UTC";
+ }
+ int seconds = static_cast<int>(offset.count());
+ const char sign = (seconds < 0 ? '-' : '+');
+ int minutes = seconds / 60;
+ seconds %= 60;
+ if (sign == '-') {
+ if (seconds > 0) {
+ seconds -= 60;
+ minutes += 1;
+ }
+ seconds = -seconds;
+ minutes = -minutes;
+ }
+ int hours = minutes / 60;
+ minutes %= 60;
+ char buf[sizeof(kFixedOffsetPrefix) + sizeof("UTC-24:00:00")];
+ snprintf(buf, sizeof(buf), "%sUTC%c%02d:%02d:%02d",
+ kFixedOffsetPrefix, sign, hours, minutes, seconds);
+ return buf;
+}
+
+std::string FixedOffsetToAbbr(const sys_seconds& offset) {
+ std::string abbr = FixedOffsetToName(offset);
+ const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
+ const char* const ep = kFixedOffsetPrefix + prefix_len;
+ if (abbr.size() >= prefix_len) {
+ if (std::equal(kFixedOffsetPrefix, ep, abbr.begin())) {
+ abbr.erase(0, prefix_len);
+ if (abbr.size() == 12) { // UTC+99:99:99
+ abbr.erase(9, 1); // UTC+99:9999
+ abbr.erase(6, 1); // UTC+999999
+ if (abbr[8] == '0' && abbr[9] == '0') { // UTC+999900
+ abbr.erase(8, 2); // UTC+9999
+ if (abbr[6] == '0' && abbr[7] == '0') { // UTC+9900
+ abbr.erase(6, 2); // UTC+99
+ if (abbr[4] == '0') { // UTC+09
+ abbr.erase(4, 1); // UTC+9
+ }
+ }
+ }
+ }
+ }
+ }
+ return abbr;
+}
+
+} // namespace cctz
+} // namespace time_internal
+} // namespace absl