aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore/core/src/firebase/firestore/timestamp.cc
diff options
context:
space:
mode:
authorGravatar Konstantin Varlamov <var-const@users.noreply.github.com>2018-03-27 11:50:03 -0400
committerGravatar GitHub <noreply@github.com>2018-03-27 11:50:03 -0400
commit22c226af3f5570514d3d13d82a399577ecd7d280 (patch)
treefc8f3e1ca146297f2993f8391ed3dab9e0f2c153 /Firestore/core/src/firebase/firestore/timestamp.cc
parent13aa61633f5a98c8dd0a508e5a404017bc79370e (diff)
C++ migration: make Timestamp class a part of public API (#944)
* move Timestamp from model/ to the root directory; * move Timestamp to top-level firebase namespace and update all references; * add conversions to and from native date types; * add a specialization of std::hash; * add comments to public member functions; * rename nanos -> nanoseconds; * add public headers, including Timestamp, to CMake; * increase test coverage.
Diffstat (limited to 'Firestore/core/src/firebase/firestore/timestamp.cc')
-rw-r--r--Firestore/core/src/firebase/firestore/timestamp.cc117
1 files changed, 117 insertions, 0 deletions
diff --git a/Firestore/core/src/firebase/firestore/timestamp.cc b/Firestore/core/src/firebase/firestore/timestamp.cc
new file mode 100644
index 0000000..7d947c5
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/timestamp.cc
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2018 Google
+ *
+ * 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 "Firestore/core/include/firebase/firestore/timestamp.h"
+
+#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+
+namespace firebase {
+
+Timestamp::Timestamp() {
+}
+
+Timestamp::Timestamp(const int64_t seconds, const int32_t nanoseconds)
+ : seconds_(seconds), nanoseconds_(nanoseconds) {
+ ValidateBounds();
+}
+
+Timestamp Timestamp::Now() {
+#if !defined(_STLPORT_VERSION)
+ // Use the standard <chrono> library from C++11 if possible.
+ return FromTimePoint(std::chrono::system_clock::now());
+#else
+ // If <chrono> is unavailable, use clock_gettime from POSIX, which supports up
+ // to nanosecond resolution. Note that it's a non-standard function contained
+ // in <time.h>.
+ //
+ // Note: it's possible to check for availability of POSIX clock_gettime using
+ // macros (see "Availability" at https://linux.die.net/man/3/clock_gettime).
+ // However, the only platform where <chrono> isn't available is Android with
+ // STLPort standard library, where clock_gettime is known to be available.
+ timespec now;
+ clock_gettime(CLOCK_REALTIME, &now);
+ return Timestamp(now.tv_sec, now.tv_nsec);
+#endif // !defined(_STLPORT_VERSION)
+}
+
+Timestamp Timestamp::FromTimeT(const time_t seconds_since_unix_epoch) {
+ return Timestamp(seconds_since_unix_epoch, 0);
+}
+
+#if !defined(_STLPORT_VERSION)
+Timestamp Timestamp::FromTimePoint(
+ const std::chrono::time_point<std::chrono::system_clock> time_point) {
+ namespace chr = std::chrono;
+ const auto epoch_time = time_point.time_since_epoch();
+ auto seconds = chr::duration_cast<chr::duration<int64_t>>(epoch_time);
+ auto nanoseconds = chr::duration_cast<chr::nanoseconds>(epoch_time - seconds);
+ FIREBASE_DEV_ASSERT(nanoseconds.count() < 1 * 1000 * 1000 * 1000);
+
+ if (nanoseconds.count() < 0) {
+ // Timestamp format always has a positive number of nanoseconds that is
+ // counting forward. For negative time, we need to transform chrono
+ // representation of (negative seconds s1 + negative nanoseconds ns1) to
+ // (negative seconds s2 + positive nanoseconds ns2). Since nanosecond part
+ // is always less than 1 second in our representation, instead of starting
+ // at s1 and going back ns1 nanoseconds, start at (s1 minus one second) and
+ // go *forward* ns2 = (1 second + ns1, ns1 < 0) nanoseconds.
+ //
+ // Note: if nanoseconds are negative, it must mean that seconds are
+ // non-positive, but the formula would still be valid, so no need to check.
+ seconds = seconds - chr::seconds(1);
+ nanoseconds = chr::seconds(1) + nanoseconds;
+ }
+
+ const Timestamp result{seconds.count(),
+ static_cast<int32_t>(nanoseconds.count())};
+ result.ValidateBounds();
+ return result;
+}
+
+#endif // !defined(_STLPORT_VERSION)
+
+std::string Timestamp::ToString() const {
+ return std::string("Timestamp(seconds=") + std::to_string(seconds_) +
+ ", nanoseconds=" + std::to_string(nanoseconds_) + ")";
+}
+
+void Timestamp::ValidateBounds() const {
+ FIREBASE_ASSERT_MESSAGE(nanoseconds_ >= 0,
+ "Timestamp nanoseconds out of range: %d",
+ nanoseconds_);
+ FIREBASE_ASSERT_MESSAGE(nanoseconds_ < 1e9,
+ "Timestamp nanoseconds out of range: %d",
+ nanoseconds_);
+ // Midnight at the beginning of 1/1/1 is the earliest timestamp Firestore
+ // supports.
+ FIREBASE_ASSERT_MESSAGE(seconds_ >= -62135596800L,
+ "Timestamp seconds out of range: %lld", seconds_);
+ // This will break in the year 10,000.
+ FIREBASE_ASSERT_MESSAGE(seconds_ < 253402300800L,
+ "Timestamp seconds out of range: %lld", seconds_);
+}
+
+} // namespace firebase
+
+namespace std {
+size_t hash<firebase::Timestamp>::operator()(
+ const firebase::Timestamp& timestamp) const {
+ // Note: if sizeof(size_t) == 4, this discards high-order bits of seconds.
+ return 37 * static_cast<size_t>(timestamp.seconds()) +
+ static_cast<size_t>(timestamp.nanoseconds());
+}
+
+} // namespace std