time_zone_posix.cc
Go to the documentation of this file.
1 // Copyright 2016 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "time_zone_posix.h"
16 
17 #include <cstddef>
18 #include <cstring>
19 #include <limits>
20 #include <string>
21 
22 namespace absl {
23 namespace time_internal {
24 namespace cctz {
25 
26 namespace {
27 
28 const char kDigits[] = "0123456789";
29 
30 const char* ParseInt(const char* p, int min, int max, int* vp) {
31  int value = 0;
32  const char* op = p;
33  const int kMaxInt = std::numeric_limits<int>::max();
34  for (; const char* dp = strchr(kDigits, *p); ++p) {
35  int d = static_cast<int>(dp - kDigits);
36  if (d >= 10) break; // '\0'
37  if (value > kMaxInt / 10) return nullptr;
38  value *= 10;
39  if (value > kMaxInt - d) return nullptr;
40  value += d;
41  }
42  if (p == op || value < min || value > max) return nullptr;
43  *vp = value;
44  return p;
45 }
46 
47 // abbr = <.*?> | [^-+,\d]{3,}
48 const char* ParseAbbr(const char* p, std::string* abbr) {
49  const char* op = p;
50  if (*p == '<') { // special zoneinfo <...> form
51  while (*++p != '>') {
52  if (*p == '\0') return nullptr;
53  }
54  abbr->assign(op + 1, static_cast<std::size_t>(p - op) - 1);
55  return ++p;
56  }
57  while (*p != '\0') {
58  if (strchr("-+,", *p)) break;
59  if (strchr(kDigits, *p)) break;
60  ++p;
61  }
62  if (p - op < 3) return nullptr;
63  abbr->assign(op, static_cast<std::size_t>(p - op));
64  return p;
65 }
66 
67 // offset = [+|-]hh[:mm[:ss]] (aggregated into single seconds value)
68 const char* ParseOffset(const char* p, int min_hour, int max_hour, int sign,
69  std::int_fast32_t* offset) {
70  if (p == nullptr) return nullptr;
71  if (*p == '+' || *p == '-') {
72  if (*p++ == '-') sign = -sign;
73  }
74  int hours = 0;
75  int minutes = 0;
76  int seconds = 0;
77 
78  p = ParseInt(p, min_hour, max_hour, &hours);
79  if (p == nullptr) return nullptr;
80  if (*p == ':') {
81  p = ParseInt(p + 1, 0, 59, &minutes);
82  if (p == nullptr) return nullptr;
83  if (*p == ':') {
84  p = ParseInt(p + 1, 0, 59, &seconds);
85  if (p == nullptr) return nullptr;
86  }
87  }
88  *offset = sign * ((((hours * 60) + minutes) * 60) + seconds);
89  return p;
90 }
91 
92 // datetime = ( Jn | n | Mm.w.d ) [ / offset ]
93 const char* ParseDateTime(const char* p, PosixTransition* res) {
94  if (p != nullptr && *p == ',') {
95  if (*++p == 'M') {
96  int month = 0;
97  if ((p = ParseInt(p + 1, 1, 12, &month)) != nullptr && *p == '.') {
98  int week = 0;
99  if ((p = ParseInt(p + 1, 1, 5, &week)) != nullptr && *p == '.') {
100  int weekday = 0;
101  if ((p = ParseInt(p + 1, 0, 6, &weekday)) != nullptr) {
102  res->date.fmt = PosixTransition::M;
103  res->date.m.month = static_cast<int_fast8_t>(month);
104  res->date.m.week = static_cast<int_fast8_t>(week);
105  res->date.m.weekday = static_cast<int_fast8_t>(weekday);
106  }
107  }
108  }
109  } else if (*p == 'J') {
110  int day = 0;
111  if ((p = ParseInt(p + 1, 1, 365, &day)) != nullptr) {
112  res->date.fmt = PosixTransition::J;
113  res->date.j.day = static_cast<int_fast16_t>(day);
114  }
115  } else {
116  int day = 0;
117  if ((p = ParseInt(p, 0, 365, &day)) != nullptr) {
118  res->date.fmt = PosixTransition::N;
119  res->date.j.day = static_cast<int_fast16_t>(day);
120  }
121  }
122  }
123  if (p != nullptr) {
124  res->time.offset = 2 * 60 * 60; // default offset is 02:00:00
125  if (*p == '/') p = ParseOffset(p + 1, -167, 167, 1, &res->time.offset);
126  }
127  return p;
128 }
129 
130 } // namespace
131 
132 // spec = std offset [ dst [ offset ] , datetime , datetime ]
133 bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res) {
134  const char* p = spec.c_str();
135  if (*p == ':') return false;
136 
137  p = ParseAbbr(p, &res->std_abbr);
138  p = ParseOffset(p, 0, 24, -1, &res->std_offset);
139  if (p == nullptr) return false;
140  if (*p == '\0') return true;
141 
142  p = ParseAbbr(p, &res->dst_abbr);
143  if (p == nullptr) return false;
144  res->dst_offset = res->std_offset + (60 * 60); // default
145  if (*p != ',') p = ParseOffset(p, 0, 24, -1, &res->dst_offset);
146 
147  p = ParseDateTime(p, &res->dst_start);
148  p = ParseDateTime(p, &res->dst_end);
149 
150  return p != nullptr && *p == '\0';
151 }
152 
153 } // namespace cctz
154 } // namespace time_internal
155 } // namespace absl
bool ParsePosixSpec(const std::string &spec, PosixTimeZone *res)
const char * abbr
Definition: duration.cc:706
std::chrono::duration< std::int_fast64_t > seconds
Definition: time_zone.h:37
Definition: algorithm.h:29
size_t value


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:19:58