256be56344
-- 00d42e3d5433aaf29c2ed293520b2ba178ae8bdb by Greg Falcon <gfalcon@google.com>: Import of CCTZ from GitHub. PiperOrigin-RevId: 238061818 -- 867a7ca318fac2991ea9a4107dbae3cc9fbf974a by Abseil Team <absl-team@google.com>: Added a IWYU export pragma when including a standard header for the purpose of aliasing its symbols. PiperOrigin-RevId: 238022277 -- 17047745058f2f151cd986ea9f649512542d3876 by Matt Armstrong <marmstrong@google.com>: Clarify the comment discouraging WrapUnique<T>(x) calls. PiperOrigin-RevId: 237873803 -- 3dcb2e4968243d33ca0ce53280c445df50f4a7ec by Samuel Benzaquen <sbenza@google.com>: Workaround clang bug https://bugs.llvm.org/show_bug.cgi?id=38289 PiperOrigin-RevId: 237873551 -- f348d2dc7087a990cbdfb95aa51fd7ff478ae40e by Samuel Benzaquen <sbenza@google.com>: Reduce minimum capacity to 1. This reduces memory usage for small tables. A flat_hash_set<int> of 1 element goes from 92 bytes to 24. A flat_hash_set<string> of 1 element goes from 512 bytes to 56. PiperOrigin-RevId: 237859811 -- 9c8125be5e4e5d22a7bb62bdec8c323338385c1b by Jon Cohen <cohenjon@google.com>: Bump to CMake 3.5. This is the oldest modern cmake being included by default in most popular OS distributions according to https://repology.org/project/cmake/versions. Specifically, Ubuntu LTS 16.04 uses cmake 3.5 (https://packages.ubuntu.com/xenial/cmake) PiperOrigin-RevId: 237859345 -- 07638d672e0a4dced986a62750cfd8318ed36ffa by Derek Mauro <dmauro@google.com>: Import of CCTZ from GitHub. PiperOrigin-RevId: 237714597 GitOrigin-RevId: 00d42e3d5433aaf29c2ed293520b2ba178ae8bdb Change-Id: I5faecc45add4a5a774d4f9baf06e5519091f2ccc
155 lines
4.6 KiB
C++
155 lines
4.6 KiB
C++
// 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
|
|
//
|
|
// https://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
|