blob: ee088f33c3942df1caa39d58c732275a25206c02 [file] [log] [blame]
mistergc2e75482017-09-19 16:54:40 -04001// Copyright 2017 The Abseil Authors.
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//
nik727338b70432019-03-08 10:27:53 -05007// https://www.apache.org/licenses/LICENSE-2.0
mistergc2e75482017-09-19 16:54:40 -04008//
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 <string.h>
16#include <cctype>
17#include <cstdint>
18
Abseil Teamaf788262018-04-23 08:17:58 -070019#include "absl/time/internal/cctz/include/cctz/time_zone.h"
mistergc2e75482017-09-19 16:54:40 -040020#include "absl/time/time.h"
Abseil Teamaf788262018-04-23 08:17:58 -070021
22namespace cctz = absl::time_internal::cctz;
mistergc2e75482017-09-19 16:54:40 -040023
24namespace absl {
Abseil Team12bc53e2019-12-12 10:36:03 -080025ABSL_NAMESPACE_BEGIN
mistergc2e75482017-09-19 16:54:40 -040026
Abseil Team37dd2562020-01-28 11:50:11 -080027ABSL_DLL extern const char RFC3339_full[] =
28 "%Y-%m-%dT%H:%M:%E*S%Ez";
29ABSL_DLL extern const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez";
mistergc2e75482017-09-19 16:54:40 -040030
Abseil Team37dd2562020-01-28 11:50:11 -080031ABSL_DLL extern const char RFC1123_full[] =
32 "%a, %d %b %E4Y %H:%M:%S %z";
33ABSL_DLL extern const char RFC1123_no_wday[] =
34 "%d %b %E4Y %H:%M:%S %z";
mistergc2e75482017-09-19 16:54:40 -040035
36namespace {
37
38const char kInfiniteFutureStr[] = "infinite-future";
39const char kInfinitePastStr[] = "infinite-past";
40
mistergc2e75482017-09-19 16:54:40 -040041struct cctz_parts {
Abseil Team4491d602018-06-21 12:55:12 -070042 cctz::time_point<cctz::seconds> sec;
43 cctz::detail::femtoseconds fem;
mistergc2e75482017-09-19 16:54:40 -040044};
45
Abseil Team4491d602018-06-21 12:55:12 -070046inline cctz::time_point<cctz::seconds> unix_epoch() {
47 return std::chrono::time_point_cast<cctz::seconds>(
mistergc2e75482017-09-19 16:54:40 -040048 std::chrono::system_clock::from_time_t(0));
49}
50
51// Splits a Time into seconds and femtoseconds, which can be used with CCTZ.
52// Requires that 't' is finite. See duration.cc for details about rep_hi and
53// rep_lo.
54cctz_parts Split(absl::Time t) {
55 const auto d = time_internal::ToUnixDuration(t);
56 const int64_t rep_hi = time_internal::GetRepHi(d);
57 const int64_t rep_lo = time_internal::GetRepLo(d);
Abseil Team4491d602018-06-21 12:55:12 -070058 const auto sec = unix_epoch() + cctz::seconds(rep_hi);
59 const auto fem = cctz::detail::femtoseconds(rep_lo * (1000 * 1000 / 4));
mistergc2e75482017-09-19 16:54:40 -040060 return {sec, fem};
61}
62
63// Joins the given seconds and femtoseconds into a Time. See duration.cc for
64// details about rep_hi and rep_lo.
65absl::Time Join(const cctz_parts& parts) {
66 const int64_t rep_hi = (parts.sec - unix_epoch()).count();
67 const uint32_t rep_lo = parts.fem.count() / (1000 * 1000 / 4);
68 const auto d = time_internal::MakeDuration(rep_hi, rep_lo);
69 return time_internal::FromUnixDuration(d);
70}
71
72} // namespace
73
Abseil Teamfebc5ee2019-03-06 11:36:55 -080074std::string FormatTime(const std::string& format, absl::Time t,
75 absl::TimeZone tz) {
mistergc2e75482017-09-19 16:54:40 -040076 if (t == absl::InfiniteFuture()) return kInfiniteFutureStr;
77 if (t == absl::InfinitePast()) return kInfinitePastStr;
78 const auto parts = Split(t);
79 return cctz::detail::format(format, parts.sec, parts.fem,
80 cctz::time_zone(tz));
81}
82
83std::string FormatTime(absl::Time t, absl::TimeZone tz) {
84 return FormatTime(RFC3339_full, t, tz);
85}
86
87std::string FormatTime(absl::Time t) {
88 return absl::FormatTime(RFC3339_full, t, absl::LocalTimeZone());
89}
90
Abseil Teamfebc5ee2019-03-06 11:36:55 -080091bool ParseTime(const std::string& format, const std::string& input,
92 absl::Time* time, std::string* err) {
mistergc2e75482017-09-19 16:54:40 -040093 return absl::ParseTime(format, input, absl::UTCTimeZone(), time, err);
94}
95
Abseil Teambed5bd62018-08-21 11:31:02 -070096// If the input string does not contain an explicit UTC offset, interpret
mistergc2e75482017-09-19 16:54:40 -040097// the fields with respect to the given TimeZone.
Abseil Teamfebc5ee2019-03-06 11:36:55 -080098bool ParseTime(const std::string& format, const std::string& input,
99 absl::TimeZone tz, absl::Time* time, std::string* err) {
mistergc2e75482017-09-19 16:54:40 -0400100 const char* data = input.c_str();
101 while (std::isspace(*data)) ++data;
102
103 size_t inf_size = strlen(kInfiniteFutureStr);
104 if (strncmp(data, kInfiniteFutureStr, inf_size) == 0) {
105 const char* new_data = data + inf_size;
106 while (std::isspace(*new_data)) ++new_data;
107 if (*new_data == '\0') {
108 *time = InfiniteFuture();
109 return true;
110 }
111 }
112
113 inf_size = strlen(kInfinitePastStr);
114 if (strncmp(data, kInfinitePastStr, inf_size) == 0) {
115 const char* new_data = data + inf_size;
116 while (std::isspace(*new_data)) ++new_data;
117 if (*new_data == '\0') {
118 *time = InfinitePast();
119 return true;
120 }
121 }
122
123 std::string error;
124 cctz_parts parts;
125 const bool b = cctz::detail::parse(format, input, cctz::time_zone(tz),
126 &parts.sec, &parts.fem, &error);
127 if (b) {
128 *time = Join(parts);
129 } else if (err != nullptr) {
130 *err = error;
131 }
132 return b;
133}
134
Abseil Teamcf6ab6b2017-09-24 08:20:48 -0700135// Functions required to support absl::Time flags.
Abseil Teamab3552a2019-10-15 18:18:40 -0700136bool AbslParseFlag(absl::string_view text, absl::Time* t, std::string* error) {
137 return absl::ParseTime(RFC3339_full, std::string(text), absl::UTCTimeZone(),
138 t, error);
139}
140
141std::string AbslUnparseFlag(absl::Time t) {
142 return absl::FormatTime(RFC3339_full, t, absl::UTCTimeZone());
143}
mistergc2e75482017-09-19 16:54:40 -0400144bool ParseFlag(const std::string& text, absl::Time* t, std::string* error) {
145 return absl::ParseTime(RFC3339_full, text, absl::UTCTimeZone(), t, error);
146}
147
148std::string UnparseFlag(absl::Time t) {
149 return absl::FormatTime(RFC3339_full, t, absl::UTCTimeZone());
150}
151
Abseil Team12bc53e2019-12-12 10:36:03 -0800152ABSL_NAMESPACE_END
mistergc2e75482017-09-19 16:54:40 -0400153} // namespace absl