Google Cloud Spanner C++ Client  1.32.0
A C++ Client Library for Google Cloud Spanner
timestamp.h
Go to the documentation of this file.
1 // Copyright 2019 Google LLC
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 // http://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 #ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_SPANNER_TIMESTAMP_H
16 #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_SPANNER_TIMESTAMP_H
17 
18 #include "google/cloud/spanner/version.h"
19 #include "google/cloud/status_or.h"
20 #include "absl/time/time.h"
21 #include <google/protobuf/timestamp.pb.h>
22 #include <chrono>
23 #include <cstdint>
24 #include <limits>
25 #include <ostream>
26 #include <string>
27 
28 namespace google {
29 namespace cloud {
30 namespace spanner {
31 inline namespace SPANNER_CLIENT_NS {
32 
33 /**
34  * Convenience alias. `std::chrono::sys_time` since C++20.
35  */
36 template <typename Duration>
37 using sys_time = std::chrono::time_point<std::chrono::system_clock, Duration>;
38 
39 /**
40  * A representation of the Spanner TIMESTAMP type: An instant in time.
41  *
42  * A `Timestamp` represents an absolute point in time (i.e., is independent of
43  * any time zone), with at least nanosecond precision, and with a range of
44  * 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z, inclusive.
45  *
46  * The `MakeTimestamp(src)` factory function(s) should be used to construct
47  * `Timestamp` values from standard representations of absolute time.
48  *
49  * A `Timestamp` can be converted back to a standard representation using
50  * `ts.get<T>()`.
51  *
52  * @see https://cloud.google.com/spanner/docs/data-types#timestamp_type
53  */
54 class Timestamp {
55  public:
56  /// Default construction yields 1970-01-01T00:00:00Z.
57  Timestamp() : Timestamp(absl::UnixEpoch()) {}
58 
59  /// @name Regular value type, supporting copy, assign, move.
60  ///@{
61  Timestamp(Timestamp&&) = default;
62  Timestamp& operator=(Timestamp&&) = default;
63  Timestamp(Timestamp const&) = default;
64  Timestamp& operator=(Timestamp const&) = default;
65  ///@}
66 
67  /// @name Relational operators
68  ///@{
69  friend bool operator==(Timestamp const& a, Timestamp const& b) {
70  return a.t_ == b.t_;
71  }
72  friend bool operator!=(Timestamp const& a, Timestamp const& b) {
73  return !(a == b);
74  }
75  friend bool operator<(Timestamp const& a, Timestamp const& b) {
76  return a.t_ < b.t_;
77  }
78  friend bool operator<=(Timestamp const& a, Timestamp const& b) {
79  return !(b < a);
80  }
81  friend bool operator>=(Timestamp const& a, Timestamp const& b) {
82  return !(a < b);
83  }
84  friend bool operator>(Timestamp const& a, Timestamp const& b) {
85  return b < a;
86  }
87  ///@}
88 
89  /// @name Output streaming
90  friend std::ostream& operator<<(std::ostream& os, Timestamp ts);
91 
92  /**
93  * Convert the `Timestamp` to the user-specified template type. Fails if
94  * `*this` cannot be represented as a `T`.
95  *
96  * Supported destination types are:
97  * - `absl::Time` - Since `absl::Time` can represent all possible
98  * `Timestamp` values, `get<absl::Time>()` never returns an error.
99  * - `google::protobuf::Timestamp` - Never returns an error, but any
100  * sub-nanosecond precision will be lost.
101  * - `google::cloud::spanner::sys_time<Duration>` - `Duration::rep` may
102  * not be wider than `std::int64_t`, and `Duration::period` may be no
103  * more precise than `std::nano`.
104  *
105  * @par Example
106  *
107  * @code
108  * sys_time<std::chrono::nanoseconds> tp = ...;
109  * Timestamp ts = MakeTimestamp(tp).value();
110  * assert(tp == ts.get<sys_time<std::chrono::nanoseconds>>().value());
111  * @endcode
112  */
113  template <typename T>
114  StatusOr<T> get() const {
115  // All `ConvertTo()` overloads return a `StatusOr<T>` even when they
116  // cannot actually fail (e.g., when the destination type can represent
117  // all `Timestamp` values). See individual comments below.
118  return ConvertTo(T{});
119  }
120 
121  private:
122  friend StatusOr<Timestamp> MakeTimestamp(absl::Time);
123 
124  StatusOr<std::int64_t> ToRatio(std::int64_t min, std::int64_t max,
125  std::int64_t num, std::int64_t den) const;
126 
127  // Conversion to a `std::chrono::time_point` on the system clock. May
128  // produce out-of-range errors, depending on the properties of `Duration`
129  // and the `std::chrono::system_clock` epoch.
130  template <typename Duration>
131  StatusOr<sys_time<Duration>> ConvertTo(sys_time<Duration> const&) const {
132  using Rep = typename Duration::rep;
133  using Period = typename Duration::period;
134  static_assert(std::ratio_greater_equal<Period, std::nano>::value,
135  "Duration must be no more precise than std::nano");
136  auto count =
137  ToRatio(std::numeric_limits<Rep>::min(),
138  std::numeric_limits<Rep>::max(), Period::num, Period::den);
139  if (!count) return std::move(count).status();
140  auto const unix_epoch = std::chrono::time_point_cast<Duration>(
141  sys_time<Duration>::clock::from_time_t(0));
142  return unix_epoch + Duration(static_cast<Rep>(*count));
143  }
144 
145  // Conversion to an `absl::Time`. Can never fail.
146  StatusOr<absl::Time> ConvertTo(absl::Time) const { return t_; }
147 
148  // Conversion to a `google::protobuf::Timestamp`. Can never fail, but
149  // any sub-nanosecond precision will be lost.
150  StatusOr<protobuf::Timestamp> ConvertTo(protobuf::Timestamp const&) const;
151 
152  explicit Timestamp(absl::Time t) : t_(t) {}
153 
154  absl::Time t_;
155 };
156 
157 /**
158  * Construct a `Timestamp` from an `absl::Time`. May produce out-of-range
159  * errors if the given time is beyond the range supported by `Timestamp` (see
160  * class comments above).
161  */
162 StatusOr<Timestamp> MakeTimestamp(absl::Time);
163 
164 /**
165  * Construct a `Timestamp` from a `google::protobuf::Timestamp`. May produce
166  * out-of-range errors if the given protobuf is beyond the range supported by
167  * `Timestamp` (which a valid protobuf never will).
168  */
169 StatusOr<Timestamp> MakeTimestamp(protobuf::Timestamp const&);
170 
171 /**
172  * Construct a `Timestamp` from a `std::chrono::time_point` on the system
173  * clock. May produce out-of-range errors, depending on the properties of
174  * `Duration` and the `std::chrono::system_clock` epoch. `Duration::rep` may
175  * not be wider than `std::int64_t`. Requires that `Duration::period` is no
176  * more precise than `std::nano`.
177  */
178 template <typename Duration>
179 StatusOr<Timestamp> MakeTimestamp(sys_time<Duration> const& tp) {
180  using Period = typename Duration::period;
181  static_assert(std::ratio_greater_equal<Period, std::nano>::value,
182  "Duration must be no more precise than std::nano");
183  auto const unix_epoch = std::chrono::time_point_cast<Duration>(
184  sys_time<Duration>::clock::from_time_t(0));
185  auto const period = absl::Seconds(Period::num) / Period::den;
186  auto const count = (tp - unix_epoch).count();
187  return MakeTimestamp(absl::UnixEpoch() + count * period);
188 }
189 
190 /**
191  * A sentinel type used to update a commit timestamp column.
192  *
193  * @see https://cloud.google.com/spanner/docs/commit-timestamp
194  */
196  friend bool operator==(CommitTimestamp, CommitTimestamp) { return true; }
197  friend bool operator!=(CommitTimestamp, CommitTimestamp) { return false; }
198 };
199 
200 } // namespace SPANNER_CLIENT_NS
201 } // namespace spanner
202 
203 namespace spanner_internal {
204 inline namespace SPANNER_CLIENT_NS {
205 StatusOr<spanner::Timestamp> TimestampFromRFC3339(std::string const&);
206 std::string TimestampToRFC3339(spanner::Timestamp);
207 } // namespace SPANNER_CLIENT_NS
208 } // namespace spanner_internal
209 
210 } // namespace cloud
211 } // namespace google
212 
213 #endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_SPANNER_TIMESTAMP_H