about summary refs log tree commit diff
path: root/absl/time
diff options
context:
space:
mode:
Diffstat (limited to 'absl/time')
-rw-r--r--absl/time/BUILD.bazel13
-rw-r--r--absl/time/clock.cc2
-rw-r--r--absl/time/duration.cc21
-rw-r--r--absl/time/duration_test.cc202
-rw-r--r--absl/time/format.cc4
-rw-r--r--absl/time/time.cc13
-rw-r--r--absl/time/time.h164
-rw-r--r--absl/time/time_test.cc61
8 files changed, 431 insertions, 49 deletions
diff --git a/absl/time/BUILD.bazel b/absl/time/BUILD.bazel
index da8167f93e4c..0d340f25ca3c 100644
--- a/absl/time/BUILD.bazel
+++ b/absl/time/BUILD.bazel
@@ -97,16 +97,3 @@ cc_test(
         "@com_googlesource_code_cctz//:time_zone",
     ],
 )
-
-# Used by get_current_time_test, which, due to a dependency on commandlineflags
-# and some required cleanup, is staying back in //base for now.
-cc_library(
-    name = "get_current_time_for_test",
-    testonly = 1,
-    copts = ABSL_DEFAULT_COPTS,
-    textual_hdrs = [
-        "clock.cc",
-        "clock.h",
-    ],
-    deps = ["//absl/base"],
-)
diff --git a/absl/time/clock.cc b/absl/time/clock.cc
index e2bc01bdb6a3..9ffc1c4f91d8 100644
--- a/absl/time/clock.cc
+++ b/absl/time/clock.cc
@@ -368,7 +368,7 @@ static uint64_t UpdateLastSample(
 // into the fast past.  That causes lots of register spills and reloads that
 // are unnecessary unless the slow path is taken.
 //
-// TODO(b/36012148) Remove this attribute when our compiler is smart enough
+// TODO(absl-team) Remove this attribute when our compiler is smart enough
 // to do the right thing.
 ABSL_ATTRIBUTE_NOINLINE
 static int64_t GetCurrentTimeNanosSlowPath() LOCKS_EXCLUDED(lock) {
diff --git a/absl/time/duration.cc b/absl/time/duration.cc
index 07d1082d8977..f5081955d3bd 100644
--- a/absl/time/duration.cc
+++ b/absl/time/duration.cc
@@ -641,6 +641,25 @@ timeval ToTimeval(Duration d) {
   return tv;
 }
 
+std::chrono::nanoseconds ToChronoNanoseconds(Duration d) {
+  return time_internal::ToChronoDuration<std::chrono::nanoseconds>(d);
+}
+std::chrono::microseconds ToChronoMicroseconds(Duration d) {
+  return time_internal::ToChronoDuration<std::chrono::microseconds>(d);
+}
+std::chrono::milliseconds ToChronoMilliseconds(Duration d) {
+  return time_internal::ToChronoDuration<std::chrono::milliseconds>(d);
+}
+std::chrono::seconds ToChronoSeconds(Duration d) {
+  return time_internal::ToChronoDuration<std::chrono::seconds>(d);
+}
+std::chrono::minutes ToChronoMinutes(Duration d) {
+  return time_internal::ToChronoDuration<std::chrono::minutes>(d);
+}
+std::chrono::hours ToChronoHours(Duration d) {
+  return time_internal::ToChronoDuration<std::chrono::hours>(d);
+}
+
 //
 // To/From std::string formatting.
 //
@@ -852,7 +871,7 @@ bool ParseDuration(const std::string& dur_string, Duration* d) {
   return true;
 }
 
-// TODO(b/63899288) copybara strip once dependencies are removed.
+// TODO(absl-team): Remove once dependencies are removed.
 bool ParseFlag(const std::string& text, Duration* dst, std::string* /* err */) {
   return ParseDuration(text, dst);
 }
diff --git a/absl/time/duration_test.cc b/absl/time/duration_test.cc
index ec8e17f548e6..ab98b02ac38f 100644
--- a/absl/time/duration_test.cc
+++ b/absl/time/duration_test.cc
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <chrono>  // NOLINT(build/c++11)
 #include <cmath>
 #include <cstdint>
 #include <ctime>
@@ -132,50 +133,50 @@ TEST(Duration, ToConversion) {
 #undef TEST_DURATION_CONVERSION
 }
 
-template <int64_t n>
+template <int64_t N>
 void TestToConversion() {
-  constexpr absl::Duration nano = absl::Nanoseconds(n);
-  EXPECT_EQ(n, absl::ToInt64Nanoseconds(nano));
+  constexpr absl::Duration nano = absl::Nanoseconds(N);
+  EXPECT_EQ(N, absl::ToInt64Nanoseconds(nano));
   EXPECT_EQ(0, absl::ToInt64Microseconds(nano));
   EXPECT_EQ(0, absl::ToInt64Milliseconds(nano));
   EXPECT_EQ(0, absl::ToInt64Seconds(nano));
   EXPECT_EQ(0, absl::ToInt64Minutes(nano));
   EXPECT_EQ(0, absl::ToInt64Hours(nano));
-  const absl::Duration micro = absl::Microseconds(n);
-  EXPECT_EQ(n * 1000, absl::ToInt64Nanoseconds(micro));
-  EXPECT_EQ(n, absl::ToInt64Microseconds(micro));
+  const absl::Duration micro = absl::Microseconds(N);
+  EXPECT_EQ(N * 1000, absl::ToInt64Nanoseconds(micro));
+  EXPECT_EQ(N, absl::ToInt64Microseconds(micro));
   EXPECT_EQ(0, absl::ToInt64Milliseconds(micro));
   EXPECT_EQ(0, absl::ToInt64Seconds(micro));
   EXPECT_EQ(0, absl::ToInt64Minutes(micro));
   EXPECT_EQ(0, absl::ToInt64Hours(micro));
-  const absl::Duration milli = absl::Milliseconds(n);
-  EXPECT_EQ(n * 1000 * 1000, absl::ToInt64Nanoseconds(milli));
-  EXPECT_EQ(n * 1000, absl::ToInt64Microseconds(milli));
-  EXPECT_EQ(n, absl::ToInt64Milliseconds(milli));
+  const absl::Duration milli = absl::Milliseconds(N);
+  EXPECT_EQ(N * 1000 * 1000, absl::ToInt64Nanoseconds(milli));
+  EXPECT_EQ(N * 1000, absl::ToInt64Microseconds(milli));
+  EXPECT_EQ(N, absl::ToInt64Milliseconds(milli));
   EXPECT_EQ(0, absl::ToInt64Seconds(milli));
   EXPECT_EQ(0, absl::ToInt64Minutes(milli));
   EXPECT_EQ(0, absl::ToInt64Hours(milli));
-  const absl::Duration sec = absl::Seconds(n);
-  EXPECT_EQ(n * 1000 * 1000 * 1000, absl::ToInt64Nanoseconds(sec));
-  EXPECT_EQ(n * 1000 * 1000, absl::ToInt64Microseconds(sec));
-  EXPECT_EQ(n * 1000, absl::ToInt64Milliseconds(sec));
-  EXPECT_EQ(n, absl::ToInt64Seconds(sec));
+  const absl::Duration sec = absl::Seconds(N);
+  EXPECT_EQ(N * 1000 * 1000 * 1000, absl::ToInt64Nanoseconds(sec));
+  EXPECT_EQ(N * 1000 * 1000, absl::ToInt64Microseconds(sec));
+  EXPECT_EQ(N * 1000, absl::ToInt64Milliseconds(sec));
+  EXPECT_EQ(N, absl::ToInt64Seconds(sec));
   EXPECT_EQ(0, absl::ToInt64Minutes(sec));
   EXPECT_EQ(0, absl::ToInt64Hours(sec));
-  const absl::Duration min = absl::Minutes(n);
-  EXPECT_EQ(n * 60 * 1000 * 1000 * 1000, absl::ToInt64Nanoseconds(min));
-  EXPECT_EQ(n * 60 * 1000 * 1000, absl::ToInt64Microseconds(min));
-  EXPECT_EQ(n * 60 * 1000, absl::ToInt64Milliseconds(min));
-  EXPECT_EQ(n * 60, absl::ToInt64Seconds(min));
-  EXPECT_EQ(n, absl::ToInt64Minutes(min));
+  const absl::Duration min = absl::Minutes(N);
+  EXPECT_EQ(N * 60 * 1000 * 1000 * 1000, absl::ToInt64Nanoseconds(min));
+  EXPECT_EQ(N * 60 * 1000 * 1000, absl::ToInt64Microseconds(min));
+  EXPECT_EQ(N * 60 * 1000, absl::ToInt64Milliseconds(min));
+  EXPECT_EQ(N * 60, absl::ToInt64Seconds(min));
+  EXPECT_EQ(N, absl::ToInt64Minutes(min));
   EXPECT_EQ(0, absl::ToInt64Hours(min));
-  const absl::Duration hour = absl::Hours(n);
-  EXPECT_EQ(n * 60 * 60 * 1000 * 1000 * 1000, absl::ToInt64Nanoseconds(hour));
-  EXPECT_EQ(n * 60 * 60 * 1000 * 1000, absl::ToInt64Microseconds(hour));
-  EXPECT_EQ(n * 60 * 60 * 1000, absl::ToInt64Milliseconds(hour));
-  EXPECT_EQ(n * 60 * 60, absl::ToInt64Seconds(hour));
-  EXPECT_EQ(n * 60, absl::ToInt64Minutes(hour));
-  EXPECT_EQ(n, absl::ToInt64Hours(hour));
+  const absl::Duration hour = absl::Hours(N);
+  EXPECT_EQ(N * 60 * 60 * 1000 * 1000 * 1000, absl::ToInt64Nanoseconds(hour));
+  EXPECT_EQ(N * 60 * 60 * 1000 * 1000, absl::ToInt64Microseconds(hour));
+  EXPECT_EQ(N * 60 * 60 * 1000, absl::ToInt64Milliseconds(hour));
+  EXPECT_EQ(N * 60 * 60, absl::ToInt64Seconds(hour));
+  EXPECT_EQ(N * 60, absl::ToInt64Minutes(hour));
+  EXPECT_EQ(N, absl::ToInt64Hours(hour));
 }
 
 TEST(Duration, ToConversionDeprecated) {
@@ -186,6 +187,149 @@ TEST(Duration, ToConversionDeprecated) {
   TestToConversion<-43>();
 }
 
+template <int64_t N>
+void TestFromChronoBasicEquality() {
+  using std::chrono::nanoseconds;
+  using std::chrono::microseconds;
+  using std::chrono::milliseconds;
+  using std::chrono::seconds;
+  using std::chrono::minutes;
+  using std::chrono::hours;
+
+  static_assert(absl::Nanoseconds(N) == absl::FromChrono(nanoseconds(N)), "");
+  static_assert(absl::Microseconds(N) == absl::FromChrono(microseconds(N)), "");
+  static_assert(absl::Milliseconds(N) == absl::FromChrono(milliseconds(N)), "");
+  static_assert(absl::Seconds(N) == absl::FromChrono(seconds(N)), "");
+  static_assert(absl::Minutes(N) == absl::FromChrono(minutes(N)), "");
+  static_assert(absl::Hours(N) == absl::FromChrono(hours(N)), "");
+}
+
+TEST(Duration, FromChrono) {
+  TestFromChronoBasicEquality<-123>();
+  TestFromChronoBasicEquality<-1>();
+  TestFromChronoBasicEquality<0>();
+  TestFromChronoBasicEquality<1>();
+  TestFromChronoBasicEquality<123>();
+
+  // Minutes (might, depending on the platform) saturate at +inf.
+  const auto chrono_minutes_max = std::chrono::minutes::max();
+  const auto minutes_max = absl::FromChrono(chrono_minutes_max);
+  const int64_t minutes_max_count = chrono_minutes_max.count();
+  if (minutes_max_count > kint64max / 60) {
+    EXPECT_EQ(absl::InfiniteDuration(), minutes_max);
+  } else {
+    EXPECT_EQ(absl::Minutes(minutes_max_count), minutes_max);
+  }
+
+  // Minutes (might, depending on the platform) saturate at -inf.
+  const auto chrono_minutes_min = std::chrono::minutes::min();
+  const auto minutes_min = absl::FromChrono(chrono_minutes_min);
+  const int64_t minutes_min_count = chrono_minutes_min.count();
+  if (minutes_min_count < kint64min / 60) {
+    EXPECT_EQ(-absl::InfiniteDuration(), minutes_min);
+  } else {
+    EXPECT_EQ(absl::Minutes(minutes_min_count), minutes_min);
+  }
+
+  // Hours (might, depending on the platform) saturate at +inf.
+  const auto chrono_hours_max = std::chrono::hours::max();
+  const auto hours_max = absl::FromChrono(chrono_hours_max);
+  const int64_t hours_max_count = chrono_hours_max.count();
+  if (hours_max_count > kint64max / 3600) {
+    EXPECT_EQ(absl::InfiniteDuration(), hours_max);
+  } else {
+    EXPECT_EQ(absl::Hours(hours_max_count), hours_max);
+  }
+
+  // Hours (might, depending on the platform) saturate at -inf.
+  const auto chrono_hours_min = std::chrono::hours::min();
+  const auto hours_min = absl::FromChrono(chrono_hours_min);
+  const int64_t hours_min_count = chrono_hours_min.count();
+  if (hours_min_count < kint64min / 3600) {
+    EXPECT_EQ(-absl::InfiniteDuration(), hours_min);
+  } else {
+    EXPECT_EQ(absl::Hours(hours_min_count), hours_min);
+  }
+}
+
+template <int64_t N>
+void TestToChrono() {
+  using std::chrono::nanoseconds;
+  using std::chrono::microseconds;
+  using std::chrono::milliseconds;
+  using std::chrono::seconds;
+  using std::chrono::minutes;
+  using std::chrono::hours;
+
+  EXPECT_EQ(nanoseconds(N), absl::ToChronoNanoseconds(absl::Nanoseconds(N)));
+  EXPECT_EQ(microseconds(N), absl::ToChronoMicroseconds(absl::Microseconds(N)));
+  EXPECT_EQ(milliseconds(N), absl::ToChronoMilliseconds(absl::Milliseconds(N)));
+  EXPECT_EQ(seconds(N), absl::ToChronoSeconds(absl::Seconds(N)));
+
+  constexpr auto absl_minutes = absl::Minutes(N);
+  auto chrono_minutes = minutes(N);
+  if (absl_minutes == -absl::InfiniteDuration()) {
+    chrono_minutes = minutes::min();
+  } else if (absl_minutes == absl::InfiniteDuration()) {
+    chrono_minutes = minutes::max();
+  }
+  EXPECT_EQ(chrono_minutes, absl::ToChronoMinutes(absl_minutes));
+
+  constexpr auto absl_hours = absl::Hours(N);
+  auto chrono_hours = hours(N);
+  if (absl_hours == -absl::InfiniteDuration()) {
+    chrono_hours = hours::min();
+  } else if (absl_hours == absl::InfiniteDuration()) {
+    chrono_hours = hours::max();
+  }
+  EXPECT_EQ(chrono_hours, absl::ToChronoHours(absl_hours));
+}
+
+TEST(Duration, ToChrono) {
+  using std::chrono::nanoseconds;
+  using std::chrono::microseconds;
+  using std::chrono::milliseconds;
+  using std::chrono::seconds;
+  using std::chrono::minutes;
+  using std::chrono::hours;
+
+  TestToChrono<kint64min>();
+  TestToChrono<-1>();
+  TestToChrono<0>();
+  TestToChrono<1>();
+  TestToChrono<kint64max>();
+
+  // Verify truncation toward zero.
+  const auto tick = absl::Nanoseconds(1) / 4;
+  EXPECT_EQ(nanoseconds(0), absl::ToChronoNanoseconds(tick));
+  EXPECT_EQ(nanoseconds(0), absl::ToChronoNanoseconds(-tick));
+  EXPECT_EQ(microseconds(0), absl::ToChronoMicroseconds(tick));
+  EXPECT_EQ(microseconds(0), absl::ToChronoMicroseconds(-tick));
+  EXPECT_EQ(milliseconds(0), absl::ToChronoMilliseconds(tick));
+  EXPECT_EQ(milliseconds(0), absl::ToChronoMilliseconds(-tick));
+  EXPECT_EQ(seconds(0), absl::ToChronoSeconds(tick));
+  EXPECT_EQ(seconds(0), absl::ToChronoSeconds(-tick));
+  EXPECT_EQ(minutes(0), absl::ToChronoMinutes(tick));
+  EXPECT_EQ(minutes(0), absl::ToChronoMinutes(-tick));
+  EXPECT_EQ(hours(0), absl::ToChronoHours(tick));
+  EXPECT_EQ(hours(0), absl::ToChronoHours(-tick));
+
+  // Verifies +/- infinity saturation at max/min.
+  constexpr auto inf = absl::InfiniteDuration();
+  EXPECT_EQ(nanoseconds::min(), absl::ToChronoNanoseconds(-inf));
+  EXPECT_EQ(nanoseconds::max(), absl::ToChronoNanoseconds(inf));
+  EXPECT_EQ(microseconds::min(), absl::ToChronoMicroseconds(-inf));
+  EXPECT_EQ(microseconds::max(), absl::ToChronoMicroseconds(inf));
+  EXPECT_EQ(milliseconds::min(), absl::ToChronoMilliseconds(-inf));
+  EXPECT_EQ(milliseconds::max(), absl::ToChronoMilliseconds(inf));
+  EXPECT_EQ(seconds::min(), absl::ToChronoSeconds(-inf));
+  EXPECT_EQ(seconds::max(), absl::ToChronoSeconds(inf));
+  EXPECT_EQ(minutes::min(), absl::ToChronoMinutes(-inf));
+  EXPECT_EQ(minutes::max(), absl::ToChronoMinutes(inf));
+  EXPECT_EQ(hours::min(), absl::ToChronoHours(-inf));
+  EXPECT_EQ(hours::max(), absl::ToChronoHours(inf));
+}
+
 // Used for testing the factory overloads.
 template <typename T>
 struct ImplicitlyConvertible {
@@ -248,7 +392,7 @@ TEST(Duration, FactoryOverloads) {
 }
 
 TEST(Duration, InfinityExamples) {
-  // These examples are used in the documentation in //base/time.h. They are
+  // These examples are used in the documentation in time.h. They are
   // written so that they can be copy-n-pasted easily.
 
   constexpr absl::Duration inf = absl::InfiniteDuration();
diff --git a/absl/time/format.cc b/absl/time/format.cc
index c58a886bf93a..7c88db5b00d0 100644
--- a/absl/time/format.cc
+++ b/absl/time/format.cc
@@ -127,8 +127,8 @@ bool ParseTime(const std::string& format, const std::string& input, absl::TimeZo
   return b;
 }
 
-// TODO(b/63899288) copybara strip once dependencies are removed.
-// Functions required to support absl::Time flags. See go/flags.
+// TODO(absl-team): Remove once dependencies are removed.
+// Functions required to support absl::Time flags.
 bool ParseFlag(const std::string& text, absl::Time* t, std::string* error) {
   return absl::ParseTime(RFC3339_full, text, absl::UTCTimeZone(), t, error);
 }
diff --git a/absl/time/time.cc b/absl/time/time.cc
index fd5a41b15080..ee14ba306e80 100644
--- a/absl/time/time.cc
+++ b/absl/time/time.cc
@@ -367,4 +367,17 @@ int64_t ToUniversal(absl::Time t) {
   return absl::FloorToUnit(t - absl::UniversalEpoch(), absl::Nanoseconds(100));
 }
 
+Time FromChrono(const std::chrono::system_clock::time_point& tp) {
+  return time_internal::FromUnixDuration(time_internal::FromChrono(
+      tp - std::chrono::system_clock::from_time_t(0)));
+}
+
+std::chrono::system_clock::time_point ToChronoTime(absl::Time t) {
+  using D = std::chrono::system_clock::duration;
+  auto d = time_internal::ToUnixDuration(t);
+  if (d < ZeroDuration()) d = Floor(d, FromChrono(D{1}));
+  return std::chrono::system_clock::from_time_t(0) +
+         time_internal::ToChronoDuration<D>(d);
+}
+
 }  // namespace absl
diff --git a/absl/time/time.h b/absl/time/time.h
index 302c76037e6f..6976343708be 100644
--- a/absl/time/time.h
+++ b/absl/time/time.h
@@ -361,7 +361,7 @@ Duration Hours(T n) {
 // Example:
 //
 //   absl::Duration d = absl::Milliseconds(1500);
-//   int64_t isec = ToInt64Seconds(d);    // isec == 1
+//   int64_t isec = ToInt64Seconds(d);  // isec == 1
 int64_t ToInt64Nanoseconds(Duration d);
 int64_t ToInt64Microseconds(Duration d);
 int64_t ToInt64Milliseconds(Duration d);
@@ -391,6 +391,46 @@ double ToDoubleSeconds(Duration d);
 double ToDoubleMinutes(Duration d);
 double ToDoubleHours(Duration d);
 
+// FromChrono()
+//
+// Converts any of the pre-defined std::chrono durations to an absl::Duration.
+//
+// Example:
+//
+//   std::chrono::milliseconds ms(123);
+//   absl::Duration d = absl::FromChrono(ms);
+constexpr Duration FromChrono(const std::chrono::nanoseconds& d);
+constexpr Duration FromChrono(const std::chrono::microseconds& d);
+constexpr Duration FromChrono(const std::chrono::milliseconds& d);
+constexpr Duration FromChrono(const std::chrono::seconds& d);
+constexpr Duration FromChrono(const std::chrono::minutes& d);
+constexpr Duration FromChrono(const std::chrono::hours& d);
+
+// ToChronoNanoseconds()
+// ToChronoMicroseconds()
+// ToChronoMilliseconds()
+// ToChronoSeconds()
+// ToChronoMinutes()
+// ToChronoHours()
+//
+// Converts an absl::Duration to any of the pre-defined std::chrono durations.
+// If overflow would occur, the returned value will saturate at the min/max
+// chrono duration value instead.
+//
+// Example:
+//
+//   absl::Duration d = absl::Microseconds(123);
+//   auto x = absl::ToChronoMicroseconds(d);
+//   auto y = absl::ToChronoNanoseconds(d);  // x == y
+//   auto z = absl::ToChronoSeconds(absl::InfiniteDuration());
+//   // z == std::chrono::seconds::max()
+std::chrono::nanoseconds ToChronoNanoseconds(Duration d);
+std::chrono::microseconds ToChronoMicroseconds(Duration d);
+std::chrono::milliseconds ToChronoMilliseconds(Duration d);
+std::chrono::seconds ToChronoSeconds(Duration d);
+std::chrono::minutes ToChronoMinutes(Duration d);
+std::chrono::hours ToChronoHours(Duration d);
+
 // InfiniteDuration()
 //
 // Returns an infinite `Duration`.  To get a `Duration` representing negative
@@ -445,7 +485,7 @@ inline std::ostream& operator<<(std::ostream& os, Duration d) {
 bool ParseDuration(const std::string& dur_string, Duration* d);
 
 // Flag Support
-// TODO(b/63899288) copybara strip once dependencies are removed.
+// TODO(absl-team): Remove once dependencies are removed.
 
 // ParseFlag()
 //
@@ -790,6 +830,30 @@ Time TimeFromTimeval(timeval tv);
 timespec ToTimespec(Time t);
 timeval ToTimeval(Time t);
 
+// FromChrono()
+//
+// Converts a std::chrono::system_clock::time_point to an absl::Time.
+//
+// Example:
+//
+//   auto tp = std::chrono::system_clock::from_time_t(123);
+//   absl::Time t = absl::FromChrono(tp);
+//   // t == absl::FromTimeT(123)
+Time FromChrono(const std::chrono::system_clock::time_point& tp);
+
+// ToChronoTime()
+//
+// Converts an absl::Time to a std::chrono::system_clock::time_point. If
+// overflow would occur, the returned value will saturate at the min/max time
+// point value instead.
+//
+// Example:
+//
+//   absl::Time t = absl::FromTimeT(123);
+//   auto tp = absl::ToChronoTime(t);
+//   // tp == std::chrono::system_clock::from_time_t(123);
+std::chrono::system_clock::time_point ToChronoTime(absl::Time);
+
 // RFC3339_full
 // RFC3339_sec
 //
@@ -917,7 +981,7 @@ bool ParseTime(const std::string& format, const std::string& input,
 bool ParseTime(const std::string& format, const std::string& input, TimeZone tz,
                Time* time, std::string* err);
 
-// TODO(b/63899288) copybara strip once dependencies are removed.
+// TODO(absl-team): Remove once dependencies are removed.
 
 // ParseFlag()
 // UnparseFlag()
@@ -1072,6 +1136,81 @@ constexpr int64_t NegateAndSubtractOne(int64_t n) {
 // knowledge, we would need to add-in/subtract-out UnixEpoch() respectively.
 constexpr Time FromUnixDuration(Duration d) { return Time(d); }
 constexpr Duration ToUnixDuration(Time t) { return t.rep_; }
+
+template <std::intmax_t N>
+constexpr absl::Duration FromInt64(int64_t v, std::ratio<1, N>) {
+  static_assert(0 < N && N <= 1000 * 1000 * 1000, "Unsupported ratio");
+  // Subsecond ratios cannot overflow.
+  return MakeNormalizedDuration(
+      v / N, v % N * kTicksPerNanosecond * 1000 * 1000 * 1000 / N);
+}
+constexpr absl::Duration FromInt64(int64_t v, std::ratio<60>) {
+  return Minutes(v);
+}
+constexpr absl::Duration FromInt64(int64_t v, std::ratio<3600>) {
+  return Hours(v);
+}
+
+// IsValidRep64<T>(0) is true if the expression `int64_t{std::declval<T>()}` is
+// valid. That is, if a T can be assigned to an int64_t without narrowing.
+template <typename T>
+constexpr auto IsValidRep64(int)
+    -> decltype(int64_t{std::declval<T>()}, bool()) {
+  return true;
+}
+template <typename T>
+constexpr auto IsValidRep64(char) -> bool {
+  return false;
+}
+
+// Converts a std::chrono::duration to an absl::Duration.
+template <typename Rep, typename Period>
+constexpr absl::Duration FromChrono(
+    const std::chrono::duration<Rep, Period>& d) {
+  static_assert(IsValidRep64<Rep>(0), "duration::rep is invalid");
+  return FromInt64(int64_t{d.count()}, Period{});
+}
+
+template <typename Ratio>
+int64_t ToInt64(absl::Duration d, Ratio) {
+  // Note: This may be used on MSVC, which may have a system_clock period of
+  // std::ratio<1, 10 * 1000 * 1000>
+  return ToInt64Seconds(d * Ratio::den / Ratio::num);
+}
+// Fastpath implementations for the 6 common duration units.
+inline int64_t ToInt64(absl::Duration d, std::nano) {
+  return ToInt64Nanoseconds(d);
+}
+inline int64_t ToInt64(absl::Duration d, std::micro) {
+  return ToInt64Microseconds(d);
+}
+inline int64_t ToInt64(absl::Duration d, std::milli) {
+  return ToInt64Milliseconds(d);
+}
+inline int64_t ToInt64(absl::Duration d, std::ratio<1>) {
+  return ToInt64Seconds(d);
+}
+inline int64_t ToInt64(absl::Duration d, std::ratio<60>) {
+  return ToInt64Minutes(d);
+}
+inline int64_t ToInt64(absl::Duration d, std::ratio<3600>) {
+  return ToInt64Hours(d);
+}
+
+// Converts an absl::Duration to a chrono duration of type T.
+template <typename T>
+T ToChronoDuration(absl::Duration d) {
+  using Rep = typename T::rep;
+  using Period = typename T::period;
+  static_assert(IsValidRep64<Rep>(0), "duration::rep is invalid");
+  if (time_internal::IsInfiniteDuration(d))
+    return d < ZeroDuration() ? T::min() : T::max();
+  const auto v = ToInt64(d, Period{});
+  if (v > std::numeric_limits<Rep>::max()) return T::max();
+  if (v < std::numeric_limits<Rep>::min()) return T::min();
+  return T{v};
+}
+
 }  // namespace time_internal
 
 constexpr bool operator<(Duration lhs, Duration rhs) {
@@ -1156,6 +1295,25 @@ constexpr Duration InfiniteDuration() {
   return time_internal::MakeDuration(std::numeric_limits<int64_t>::max(), ~0U);
 }
 
+constexpr Duration FromChrono(const std::chrono::nanoseconds& d) {
+  return time_internal::FromChrono(d);
+}
+constexpr Duration FromChrono(const std::chrono::microseconds& d) {
+  return time_internal::FromChrono(d);
+}
+constexpr Duration FromChrono(const std::chrono::milliseconds& d) {
+  return time_internal::FromChrono(d);
+}
+constexpr Duration FromChrono(const std::chrono::seconds& d) {
+  return time_internal::FromChrono(d);
+}
+constexpr Duration FromChrono(const std::chrono::minutes& d) {
+  return time_internal::FromChrono(d);
+}
+constexpr Duration FromChrono(const std::chrono::hours& d) {
+  return time_internal::FromChrono(d);
+}
+
 constexpr Time FromUnixNanos(int64_t ns) {
   return time_internal::FromUnixDuration(Nanoseconds(ns));
 }
diff --git a/absl/time/time_test.cc b/absl/time/time_test.cc
index 51b9e53d6905..64083880c1e0 100644
--- a/absl/time/time_test.cc
+++ b/absl/time/time_test.cc
@@ -14,6 +14,7 @@
 
 #include "absl/time/time.h"
 
+#include <chrono>  // NOLINT(build/c++11)
 #include <cstring>
 #include <ctime>
 #include <iomanip>
@@ -489,6 +490,66 @@ TEST(Time, RoundtripConversion) {
 #undef TEST_CONVERSION_ROUND_TRIP
 }
 
+template <typename Duration>
+std::chrono::system_clock::time_point MakeChronoUnixTime(const Duration& d) {
+  return std::chrono::system_clock::from_time_t(0) + d;
+}
+
+TEST(Time, FromChrono) {
+  EXPECT_EQ(absl::FromTimeT(-1),
+            absl::FromChrono(std::chrono::system_clock::from_time_t(-1)));
+  EXPECT_EQ(absl::FromTimeT(0),
+            absl::FromChrono(std::chrono::system_clock::from_time_t(0)));
+  EXPECT_EQ(absl::FromTimeT(1),
+            absl::FromChrono(std::chrono::system_clock::from_time_t(1)));
+
+  EXPECT_EQ(
+      absl::FromUnixMillis(-1),
+      absl::FromChrono(MakeChronoUnixTime(std::chrono::milliseconds(-1))));
+  EXPECT_EQ(absl::FromUnixMillis(0),
+            absl::FromChrono(MakeChronoUnixTime(std::chrono::milliseconds(0))));
+  EXPECT_EQ(absl::FromUnixMillis(1),
+            absl::FromChrono(MakeChronoUnixTime(std::chrono::milliseconds(1))));
+
+  // Chrono doesn't define exactly its range and precision (neither does
+  // absl::Time), so let's simply test +/- ~100 years to make sure things work.
+  const auto century_sec = 60 * 60 * 24 * 365 * int64_t{100};
+  const auto century = std::chrono::seconds(century_sec);
+  const auto chrono_future = MakeChronoUnixTime(century);
+  const auto chrono_past = MakeChronoUnixTime(-century);
+  EXPECT_EQ(absl::FromUnixSeconds(century_sec),
+            absl::FromChrono(chrono_future));
+  EXPECT_EQ(absl::FromUnixSeconds(-century_sec), absl::FromChrono(chrono_past));
+
+  // Roundtrip them both back to chrono.
+  EXPECT_EQ(chrono_future,
+            absl::ToChronoTime(absl::FromUnixSeconds(century_sec)));
+  EXPECT_EQ(chrono_past,
+            absl::ToChronoTime(absl::FromUnixSeconds(-century_sec)));
+}
+
+TEST(Time, ToChronoTime) {
+  EXPECT_EQ(std::chrono::system_clock::from_time_t(-1),
+            absl::ToChronoTime(absl::FromTimeT(-1)));
+  EXPECT_EQ(std::chrono::system_clock::from_time_t(0),
+            absl::ToChronoTime(absl::FromTimeT(0)));
+  EXPECT_EQ(std::chrono::system_clock::from_time_t(1),
+            absl::ToChronoTime(absl::FromTimeT(1)));
+
+  EXPECT_EQ(MakeChronoUnixTime(std::chrono::milliseconds(-1)),
+            absl::ToChronoTime(absl::FromUnixMillis(-1)));
+  EXPECT_EQ(MakeChronoUnixTime(std::chrono::milliseconds(0)),
+            absl::ToChronoTime(absl::FromUnixMillis(0)));
+  EXPECT_EQ(MakeChronoUnixTime(std::chrono::milliseconds(1)),
+            absl::ToChronoTime(absl::FromUnixMillis(1)));
+
+  // Time before the Unix epoch should floor, not trunc.
+  const auto tick = absl::Nanoseconds(1) / 4;
+  EXPECT_EQ(std::chrono::system_clock::from_time_t(0) -
+                std::chrono::system_clock::duration(1),
+            absl::ToChronoTime(absl::UnixEpoch() - tick));
+}
+
 TEST(Time, ConvertDateTime) {
   const absl::TimeZone utc = absl::UTCTimeZone();
   const absl::TimeZone goog =