From 22c226af3f5570514d3d13d82a399577ecd7d280 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 27 Mar 2018 11:50:03 -0400 Subject: 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. --- Firestore/core/src/firebase/firestore/timestamp.cc | 117 +++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 Firestore/core/src/firebase/firestore/timestamp.cc (limited to 'Firestore/core/src/firebase/firestore/timestamp.cc') 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 library from C++11 if possible. + return FromTimePoint(std::chrono::system_clock::now()); +#else + // If is unavailable, use clock_gettime from POSIX, which supports up + // to nanosecond resolution. Note that it's a non-standard function contained + // in . + // + // 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 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 time_point) { + namespace chr = std::chrono; + const auto epoch_time = time_point.time_since_epoch(); + auto seconds = chr::duration_cast>(epoch_time); + auto nanoseconds = chr::duration_cast(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(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::operator()( + const firebase::Timestamp& timestamp) const { + // Note: if sizeof(size_t) == 4, this discards high-order bits of seconds. + return 37 * static_cast(timestamp.seconds()) + + static_cast(timestamp.nanoseconds()); +} + +} // namespace std -- cgit v1.2.3